Skip to main content
EMAIL API Preview

Send an email v1

Send emails from your CRM, application, or backend.

POST/v1/messages
AUTHENTICATION
Bearer API key
REQUEST RATE (per workspace)
1,000 / 10 seconds
RECIPIENTS (To + Cc + Bcc)
One or more
BODY LIMIT
1 MB

Request headers​

HeaderValue
AuthorizationBearer YOUR_API_KEY — replace the placeholder with your workspace API key.
Content-Typeapplication/json

Body Parameters​

fromstringRequired

The email address recipients see as the sender. Use an address on a domain configured for sending in your SendMero workspace. Supply the address alone; set the sender's display name with from_name.

Examplebilling@example.com
from_namestringOptional

The name shown beside the sender's address, such as your company or support team's name. Accepts 1–100 characters after trimming spaces. Do not include an email address, <, >, @, or control characters.

ExampleExample Billing
tostring | string[]Required

The main recipient's email address, or an array of addresses when several people should receive the same email. Supply at least one address. See Address format below.

Example["alex@example.net", "sam@example.net"]
ccstring | string[]Optional

Recipients who should receive a visible copy, such as the customer's account manager. Use one address or an array of addresses. Omit this field when no copy is needed.

Example["accounts@example.net"]
bccstring | string[]Optional

Recipients who should receive a blind copy without being listed in the email's To or Cc fields. For example, copy an internal archive mailbox.

Examplearchive@example.com
reply_tostring | string[]Optional

Where replies should go when it differs from from. Use this to route replies from a billing address to your support team. Accepts one address or an array of up to five distinct addresses; comparison ignores case.

Examplesupport@example.com

Address format​

Use a bare address such as alex@example.net. For multiple recipients, use a JSON array; neither a comma-separated string nor "Alex <alex@example.net>" is accepted. Remove duplicate recipients in your application before sending. Address fields and the subject must not contain line breaks or null characters.

Subject and content​

subjectstringRequired

The subject recipients see in their inbox. Supply a nonempty string. Build any personalized subject, such as an invoice number or customer's name, in your application before sending.

ExampleYour invoice INV-1042 is ready
textstringtext or html

The plain-text version of the email. Use it on its own for a text email, or include it alongside html as an alternative for email clients that display plain text.

ExampleHi Alex, your invoice INV-1042 is ready. View it at https://example.com/invoices/INV-1042.
htmlstringtext or html

The formatted version of the email, including headings, links, and images. Send the finished HTML after rendering your application's template. Include text too if you want a plain-text alternative; the API does not generate one for you.

Example<p>Hi Alex,</p><p>Your <a href="https://example.com/invoices/INV-1042">invoice INV-1042</a> is ready.</p>

Attachments and application data​

attachmentsobject[]Optional

Files to include with the email, such as an invoice or receipt. Read the file in your application, encode its bytes as Base64, and include one object per file. The example contains a text file with the contents Hello!.

PropertyTypeDescription
filenamestring, requiredThe file name shown to the recipient, including its extension.
contentstring, requiredThe file's Base64-encoded content, not a file path or download URL.
content_typestring, optionalThe MIME type, such as application/pdf or text/plain.

The complete JSON request, including encoded files, must fit within 1 MB. Base64 adds to the original file size, so check the encoded request size before sending.

Example[{"filename":"receipt.txt","content":"SGVsbG8h","content_type":"text/plain"}]
metadataobject<string, string>Optional

Your application's identifiers for this email. For a CRM integration, include a contact, deal, or invoice ID so you can associate the returned message ID with the correct record. The API echoes this object in its successful response; it does not add metadata to the email or use it to personalize the content.

Accepts up to 10 keys with string values. Keys must be 1–40 letters, digits, or underscores; values may contain up to 256 characters. The complete metadata object must fit within 2,048 UTF-8 bytes as JSON. Convert numeric IDs to strings.

Example{"contact_id":"contact-123","invoice_id":"INV-1042"}
unsubscribe_headerstringOptional

For a message from a transactional sending domain: "on" adds SendMero's one-click unsubscribe headers to this message. The default (auto, or leaving it out) adds none. Messages from a marketing domain always get a working one-click header, so this field is ignored there. See Unsubscribe links.

Example"on"
unsubscribe_linkstringOptional

For a message from a transactional sending domain: "on" adds SendMero's small "Unsubscribe" link at the bottom of the message when it does not contain the {{sendmero_unsubscribe_url}} placeholder. The default adds nothing. Marketing domains always get the link when the message does not contain the placeholder. See Unsubscribe links.

Example"on"
headersobject<string, string>Optional

Additional email headers for integrations that need them. Use metadata for internal CRM IDs; use headers when the value needs to be part of the email itself. These are email headers, separate from the HTTP request headers used to call the API. See Custom header rules.

Example{"X-Invoice-Id":"INV-1042"}

Successful responses​

Email accepted: HTTP 200​

The API returns accepted after the email has been queued. If you included metadata, it is returned unchanged:

{
"id": "msg_00000000000000000000000000000001",
"status": "accepted",
"metadata": {
"contact_id": "contact-123",
"invoice_id": "INV-1042"
}
}
FieldHow to use it
idSave this SendMero message ID alongside the email activity in your CRM.
statusaccepted means queued for processing. It does not confirm delivery to the recipient's inbox.
metadataYour original application data. Present only when supplied in the request.

Record the email as queued in your application when you receive this response. This endpoint does not return individual recipient statuses, and there is currently no API endpoint to look up delivery status by message ID.

Response headers​

HeaderPurpose
X-Request-IdIdentifies this API call. Save it with failures to help investigate a problem.
Cache-Controlno-store.
Retry-AfterPresent on 429 responses. The number of seconds to wait before retrying.

Errors​

When a request fails, the API returns a non-200 HTTP status and an error object. Use error.code for application logic and error.message to explain what needs fixing. Validation errors name the first invalid field, for example:

{
"error": {
"code": "invalid_request",
"message": "text: text or html is required",
"request_id": "req_00000000000000000000000000000001"
}
}
HTTPError codeWhat to do
400invalid_jsonSerialize the body as valid JSON.
401missing_api_keyAdd the Authorization: Bearer YOUR_API_KEY header.
401invalid_api_keyCheck that the full key is correct, active, and unexpired.
404not_foundCheck the URL: /v1/messages.
405method_not_allowedUse POST for this endpoint.
413message_too_largeReduce the complete JSON body to 1 MB or less, including attachments.
415unsupported_media_typeSet Content-Type: application/json.
422invalid_requestCorrect the field named in error.message, then submit again.
429rate_limit_exceededWait for the time in Retry-After before retrying.
503service_unavailableThe service could not complete the request. Keep the request ID and investigate an uncertain send before submitting it again.

Handle retries​

For a 429 response, delay the request by the number of seconds in Retry-After. Coordinate sending across your application: API keys for the same workspace share its rate limit.

For a timeout, lost connection, or 503, the outcome may be uncertain. The email may already have been queued. Each POST is a new submission, and the API does not deduplicate repeated requests or offer an idempotency key. Record the result against your CRM activity and resolve an uncertain attempt before resending. Reusing the same metadata does not prevent duplicates.

Custom header rules​

Use the headers object only when you need additional email headers. For standard fields such as the subject, sender, recipients, and reply address, use the corresponding request fields.

RuleLimit
Header countUp to 10 headers.
Name1–76 letters, digits, or hyphens; no leading or trailing hyphen. Names must be unique ignoring case.
Value1–998 printable ASCII characters; tabs are allowed, line breaks are not.
Total sizeUp to 8,192 bytes for the headers object as JSON.
Reserved header names

SendMero manages the headers below. Setting one returns 422 invalid_request. Names are case-insensitive, and * means every name with that prefix.

AreaReserved headers
Message fieldsFrom, To, Cc, Bcc, Subject, Reply-To, Sender, Message-ID, Date, MIME-Version, In-Reply-To, References, Content-*, Resent-*
RoutingReturn-Path, Received, Delivered-To, X-Original-To, Errors-To, Bounces-To, TLS-Required, Require-Recipient-Valid-Since
AuthenticationDKIM-Signature, DomainKey-Signature, ARC-*, Authentication-Results, Received-SPF
FeedbackFeedback-ID, CFBL-Address, CFBL-Feedback-ID, X-Report-Abuse, X-Abuse-*, Return-Receipt-To, Disposition-Notification-To
Delivery controlsX-Spam-*, X-MS-Exchange-*, X-Forefront-*, X-Originating-IP, X-Priority, Importance, Priority, Precedence, Auto-Submitted
Platform headersX-SendMero-* and the other X- headers the platform adds itself

Unsubscribe headers​

If your application provides an unsubscribe handler, include its HTTPS or mailto URL inside angle brackets. For one-click unsubscribe, supply the exact List-Unsubscribe-Post value below and an HTTPS link in List-Unsubscribe:

{
"headers": {
"List-Unsubscribe": "<https://example.com/unsubscribe/contact-123>",
"List-Unsubscribe-Post": "List-Unsubscribe=One-Click"
}
}

Add this headers object to a complete email request. Your application must handle the unsubscribe action at that URL.