Attachments & Inline Images
Include files in the attachments array of a Send Email request. Each item contains the file's name and Base64-encoded bytes. You can include up to 20 attachments in one request; omitting the array is equivalent to an empty list.
These field rules are for the REST API. Over SMTP, attach files with your mail library as usual; each one arrives as an attachment. Inline images (cid: references) arrive as ordinary attachments, and the whole message must stay within about 90 KB. See SMTP.
Use an administrator-provided endpoint with an activated API key and sender domain. Test mode validates attachment fields without sending email. Production accepted confirms queued processing; it does not confirm delivery or how an email client will display an attachment.
Attachment fields
All four fields below are strings. Unknown fields are rejected.
| Field | Required | Rules |
|---|---|---|
filename | Yes | A nonblank recipient-facing filename, such as receipt.txt. Line breaks and other control characters are rejected. This is not a path the API reads. |
content | Yes | The file's bytes encoded as standard canonical Base64. Supply the content itself, not a URL, file path, or data URL. |
content_type | No | A plain MIME type such as text/plain, image/png, or application/pdf. Use a single type/subtype; parameters such as ; charset=utf-8 are not supported. |
content_id | No | A bare ID used to reference this file from HTML, such as logo. IDs must be unique within the request. See Inline images. |
Base64 and request size
Encode the original file bytes using standard Base64: A–Z, a–z, 0–9, +, and /, with = padding where needed. Do not insert whitespace or line wrapping. URL-safe Base64 containing - or _, a data:...;base64, prefix, and noncanonical encodings are rejected. For example, SGVsbG8h represents the six bytes in Hello!.
The entire JSON request must be at most 1,000,000 UTF-8 bytes, including all Base64 strings, email content, metadata, JSON punctuation, whitespace, and escaping. This is a combined limit, not an allowance per attachment or for the decoded files. Base64 usually adds about one-third to a file's size before JSON overhead, so measure the final serialized request you will send.
Send uncompressed JSON with Content-Type: application/json. The API does not download attachment URLs or read local paths. See Rate Limits & Retries for the upload deadline and other limits.
Send a text attachment
This complete request attaches a text file containing Hello!. It uses test mode, so successful validation creates no production send.
Run this request from your backend. Replace YOUR_API_KEY with your full workspace API key, including its live_ prefix, as described in Authentication. Replace the sender with an address on your configured domain and the recipient with your test address. Repeating a POST is a separate request; test mode prevents a production send but still uses request rate.
curl --request POST 'https://api.sendmero.com/v1/messages' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data-raw '{
"from": "Example App <hello@example.com>",
"to": ["recipient@example.net"],
"reply_to": "support@example.com",
"subject": "Your receipt",
"text": "Your receipt is attached.",
"attachments": [
{
"filename": "receipt.txt",
"content": "SGVsbG8h",
"content_type": "text/plain"
}
],
"headers": { "X-Order-Id": "order-123" },
"tags": [{ "name": "category", "value": "receipt" }],
"metadata": { "order_id": "order-123" },
"options": { "test_mode": true, "require_tls": true }
}'
A successful test returns HTTP 200 with status: "validated". See Test Mode before changing this into a production request. Submit production requests once and investigate any uncertain outcome before posting again.
Inline images
Set an attachment's content_id to a bare ID, then use cid: plus that ID in the HTML. For example, content_id: "logo" matches src="cid:logo".
Content IDs must contain visible ASCII characters and must not contain whitespace, angle brackets, double quotes, or backslashes. Do not put the cid: prefix in content_id. IDs are case-sensitive and must be unique within the request; use exactly the same spelling in your HTML reference.
This complete JSON body includes a transparent 1×1 PNG. Submit it to the same POST /v1/messages endpoint with the same authentication and JSON content-type headers:
{
"from": "Example App <hello@example.com>",
"to": ["recipient@example.net"],
"subject": "Welcome to Example App",
"text": "Welcome to Example App. Your account is ready.",
"html": "<p>Welcome to Example App.</p><img src=\"cid:logo\" alt=\"Example App logo\">",
"attachments": [
{
"filename": "logo.png",
"content": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAC0lEQVR4nGNgAAIAAAUAAXpeqz8AAAAASUVORK5CYII=",
"content_type": "image/png",
"content_id": "logo"
}
],
"options": { "test_mode": true }
}
Replace the PNG bytes with your image's Base64 content for your own email. Test mode checks the request and attachment rules; it does not render HTML or verify that every cid: reference matches an attachment. Check those references in your application.
Attachment errors
| HTTP and code | What to check |
|---|---|
422 invalid_attachment | Attachment count, required fields and their types, filename safety, canonical Base64, MIME type, and content-ID format or duplicates. error.details identifies the affected field when available. |
422 unsupported_parameter | Remove unknown attachment fields. Use the four documented fields only. |
413 message_too_large | Measure and reduce the complete encoded JSON request, including its whitespace and attachment content. |
408 request_timeout | The body upload exceeded its deadline. Check the connection and request size. A returned not_accepted outcome allows another attempt; if no usable response arrived, investigate before posting again. See Rate Limits & Retries. |
Authentication, sender, and rate-limit errors can also occur. The Error Codes page covers all public errors; the Send Email reference covers the remaining request fields and response contract.