Attachments
Attach files to a send with base64 content, embed inline images with cid, and stay inside the 40 MiB message ceiling.
Any send can carry an attachments array. Each entry is a file: a name, the bytes as base64, and optionally a MIME type and a Content-ID. A message with at least one attachment is assembled as a full MIME message rather than the plain subject-and-body form.
The attachment object
| Field | Type | Required | Behavior |
|---|---|---|---|
filename | string | yes | The name the recipient sees. |
content | string | yes | The file's bytes, base64-encoded. Bare base64 only, with no data: URI prefix. |
contentType | string | no | MIME type, for example application/pdf. Omit it and the type is derived from filename. |
cid | string | no | Content-ID. Setting it makes the part inline rather than a listed attachment. See Inline images. |
contentType and cid are camelCase, unlike the snake_case fields elsewhere in the send body. Unknown keys are ignored, so content_type is not read and the type comes from filename.
Attach a file
curl -X POST https://api.mailfully.com/v1/emails \
-H "Authorization: Bearer mf_live_xxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"from": "billing@mail.acme.com",
"to": "you@yourcompany.com",
"subject": "Invoice 4212",
"text": "Invoice 4212 is attached.",
"attachments": [
{
"filename": "invoice-4212.pdf",
"content": "JVBERi0xLjQKJeLjz9MKMyAwIG9iago8PC9UeXBlL...",
"contentType": "application/pdf"
}
]
}'The response is the standard 202 acceptance. Attachments are not echoed back, the same way html and text are not.
In the SDK, attachments is typed unknown[] and sent as-is, so TypeScript will not catch a misspelled filename. The API will: a bad entry comes back as a 422 naming it by index.
Inline images
Give an attachment a cid and it becomes part of the message body rather than a file listed at the bottom. Reference it from your HTML with cid: and the same value:
{
"from": "news@mail.acme.com",
"to": "you@yourcompany.com",
"subject": "This month at Acme",
"html": "<p>Hello.</p><img src=\"cid:header-logo\" alt=\"Acme\">",
"attachments": [
{
"filename": "logo.png",
"content": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAA...",
"contentType": "image/png",
"cid": "header-logo"
}
]
}
Pick a cid that is unique within the message. Whether the image renders is up to the receiving client, and many hold images until the reader allows them, so keep the alt text meaningful and never put content only in an image.
Size limit
The ceiling is 40 MiB (41,943,040 bytes) of base64, totaled across every attachment on the message. Base64 inflates bytes by about a third, so that budget is roughly 30 MiB of original file.
The limit is per message, not per file. A batch of 100 gets 40 MiB each, not 40 MiB between them.
Going over returns a 422 on the send, with param set to attachments.
Validation
Attachments are validated when the request is received. A malformed attachment returns a 422 with the standard error envelope, and param names the offending entry by index. Nothing is silently dropped.
| Rejected | param |
|---|---|
filename missing, not a string, or empty | attachments.<i>.filename |
content missing, not a string, or empty | attachments.<i>.content |
content carries a data: URI prefix | attachments.<i>.content |
content is not base64 | attachments.<i>.content |
| Total base64 across all attachments exceeds 41,943,040 bytes | attachments |
So a bad content on the first attachment reports as attachments.0.content.
Line-wrapped base64 and the URL-safe base64 alphabet (- and _) are both accepted.
Attachments elsewhere
- Batch:
POST /v1/emails/batchtakes the same object per entry, with the same rules. - Templates: a template supplies
htmlandtext; attachments stay on the send. Templates cannot carry them. - Test mode: attachments are sent as in live mode. See Test mode for what changes.
- Scheduled sends: attachments are validated when you schedule the send, not when it dispatches. See Scheduled sends.
Related
- The
attachmentsfield onPOST /v1/emails - How sending works for the full lifecycle and what
202covers - Errors for the error envelope
