Skip to main content

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.

Sending over SMTP

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.

Submission preview

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.

FieldRequiredRules
filenameYesA nonblank recipient-facing filename, such as receipt.txt. Line breaks and other control characters are rejected. This is not a path the API reads.
contentYesThe file's bytes encoded as standard canonical Base64. Supply the content itself, not a URL, file path, or data URL.
content_typeNoA 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_idNoA 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 codeWhat to check
422 invalid_attachmentAttachment 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_parameterRemove unknown attachment fields. Use the four documented fields only.
413 message_too_largeMeasure and reduce the complete encoded JSON request, including its whitespace and attachment content.
408 request_timeoutThe 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.