How-to
Attachments
Attach files to API emails as base64 content or from a URL, embed inline images with Content-ID, and stay within allowed file types and size limits.
This page shows how to attach files to emails you send with POST /emails, either as base64-encoded content or by letting Emailit download them from a URL. It also covers inline images, allowed file types and size limits.
Attachment fields
Pass an attachments array. Each item is an object with these fields:
filenamestringrequiredcontentstringcontent or url, not both.urlstringhttp:// or https:// URL that Emailit downloads the file from. Use either content or url, not both.content_typestringapplication/pdf. Required with content. With url, it defaults to the Content-Type the server returns.content_idstringcid:.encodingstringdefault: base64content is encoded. Leave it as base64 unless you have a reason to change it.Attach a file as base64
Read the file, encode it as base64, and send it with its MIME type.
curl https://api.emailit.com/v2/emails \
-H "Authorization: Bearer $EMAILIT_API_KEY" \
-H "Content-Type: application/json" \
-d "{
\"from\": \"Acme Billing <billing@acme.com>\",
\"to\": \"ada@example.com\",
\"subject\": \"Invoice INV-1042\",
\"text\": \"Your invoice is attached.\",
\"attachments\": [{
\"filename\": \"INV-1042.pdf\",
\"content\": \"$(base64 < INV-1042.pdf | tr -d '\n')\",
\"content_type\": \"application/pdf\"
}]
}"import { readFile } from 'node:fs/promises';
import { Emailit } from '@emailit/node';
const emailit = new Emailit(process.env.EMAILIT_API_KEY);
const pdf = await readFile('INV-1042.pdf');
await emailit.emails.send({
from: 'Acme Billing <billing@acme.com>',
to: 'ada@example.com',
subject: 'Invoice INV-1042',
text: 'Your invoice is attached.',
attachments: [
{
filename: 'INV-1042.pdf',
content: pdf.toString('base64'),
content_type: 'application/pdf',
},
],
});import base64
import os
from emailit import EmailitClient
client = EmailitClient(os.environ["EMAILIT_API_KEY"])
with open("INV-1042.pdf", "rb") as f:
pdf = base64.b64encode(f.read()).decode("ascii")
client.emails.send({
"from": "Acme Billing <billing@acme.com>",
"to": "ada@example.com",
"subject": "Invoice INV-1042",
"text": "Your invoice is attached.",
"attachments": [{
"filename": "INV-1042.pdf",
"content": pdf,
"content_type": "application/pdf",
}],
})$emailit = Emailit::client(getenv('EMAILIT_API_KEY'));
$emailit->emails()->send([
'from' => 'Acme Billing <billing@acme.com>',
'to' => 'ada@example.com',
'subject' => 'Invoice INV-1042',
'text' => 'Your invoice is attached.',
'attachments' => [[
'filename' => 'INV-1042.pdf',
'content' => base64_encode(file_get_contents('INV-1042.pdf')),
'content_type' => 'application/pdf',
]],
]);Attach a file from a URL
Instead of encoding the file yourself, give Emailit a url. Emailit downloads the file while it builds the message, so the request takes as long as the download.
{
"from": "Acme Billing <billing@acme.com>",
"to": "ada@example.com",
"subject": "Invoice INV-1042",
"text": "Your invoice is attached.",
"attachments": [
{
"filename": "INV-1042.pdf",
"url": "https://files.acme.com/invoices/INV-1042.pdf"
}
]
}The URL has to meet these rules, or the request fails with 422 and Attachment error:
- It uses
httporhttpsand points to a public host. Private and internal addresses are refused. - It returns the file directly with a
2xxstatus. Redirects aren’t followed. - The download finishes within 30 seconds.
- The file is no larger than 25 MB, as reported by its
Content-Lengthheader.
Emailit builds a separate copy of the message for each recipient and downloads URL attachments for each copy. Make sure signed or expiring URLs stay valid for the whole request, and that the file host can handle one download per recipient.
Embed inline images
To show an image inside the HTML body instead of as a separate attachment, give it a content_id and reference that ID with cid: in an img tag.
{
"from": "Acme <hello@acme.com>",
"to": "ada@example.com",
"subject": "Your weekly report",
"html": "<p><img src=\"cid:chart-week-40\" alt=\"Weekly signups\" width=\"600\"></p>",
"attachments": [
{
"filename": "chart.png",
"content": "iVBORw0KGgoAAAANSUhEUgAA...",
"content_type": "image/png",
"content_id": "chart-week-40"
}
]
}The content_id in the attachment and the value after cid: must match exactly. Inline images make the message larger for every recipient, so for logos and other shared images, a hosted image URL in the HTML is usually the better choice.
Size limits
| Limit | Value |
|---|---|
| Whole message, after encoding | 40 MB. Larger messages fail with 413 Message too large. |
One attachment downloaded from url |
25 MB |
Download timeout for url |
30 seconds |
| JSON request body | 50 MB |
Base64 encoding makes files about a third larger, and the 40 MB limit applies to the encoded message. In practice, keep the combined size of your files under about 29 MB. For anything bigger, upload the file to your own storage and send a link.
Allowed file types
filename must end in one of these extensions. Any other extension, or a name without an extension, fails validation with 400.
| Category | Extensions |
|---|---|
| Text | .txt, .csv, .log, .css, .ics, .xml |
| Images | .jpg, .jpe, .jpeg, .gif, .png, .bmp, .psd, .tif, .tiff, .svg, .indd, .ai, .eps |
| Documents | .doc, .docx, .rtf, .odt, .ott, .pdf, .pub, .pages, .mobi, .epub |
| Audio | .mp3, .m4a, .m4v, .wma, .ogg, .flac, .wav, .aif, .aifc, .aiff |
| Video | .mp4, .mov, .avi, .mkv, .mpeg, .mpg, .wmv |
| Spreadsheets | .xls, .xlsx, .ods, .numbers |
| Presentations | .odp, .ppt, .pptx, .pps, .key |
| Archives and contacts | .zip, .vcf |
.eml |
|
| Signatures and encryption | .p7c, .p7m, .p7s, .pgp, .asc, .sig |
Executable files and scripts aren’t on the list and can’t be attached.
Read the attachments of a sent email
List attachments (GET /emails/{id}/attachments) returns each attachment with its filename, content_type, size, content_id, content_disposition (attachment or inline) and base64 content. It needs a Full Access key. Attachments are deleted together with the message contents when your data retention period ends.
Troubleshooting
| Error | What to check |
|---|---|
Attachment at index 0 missing content_type (required when using 'content') |
Add content_type to every base64 attachment. |
Attachment 'report.exe' has unsupported file type '.exe' |
Use an allowed extension, or put the file in a .zip. |
Attachment at index 0 cannot have both 'content' and 'url' |
Send one of the two. |
Attachment error with Failed to fetch attachment |
The URL returned an error status, redirected, timed out or isn’t public. Open it from a server outside your network to check. |
Attachment error with Attachment too large (max 25MB) |
Host the file and send a link instead. |
413 Message too large |
Reduce the total size of attachments. |
Related
- Send an email
- Send an email API reference
- Data retention