Email API
Sending email
Send one message or a batch, now or later — with attachments, tags and idempotency.
Every recipient — to, cc and bcc — counts once against your plan's monthly allowance. Send an Idempotency-Key header with anything you might retry: the same key returns the first answer instead of sending twice, for 24 hours.
Send an email
emailapi.mercestack.com/v1/emailSends one message from a verified domain. Give html, text or a template — at least one. With scheduledAt it is held and sent then (attachments cannot be scheduled).
Body
fromstringrequired[email protected]orAcme <[email protected]>, on a domain verified and marked for transactional email.tostring | string[]required- 50 recipients at most across
to,ccandbcc. ccstring | string[]- Copied.
bccstring | string[]- Blind-copied: only in the envelope, never a header.
subjectstring- Required unless a template supplies it.
htmlstring- The HTML body.
textstring- The plain-text body; made from
htmlwhen left out. templatestring- A stored template's alias or id. Its subject and bodies fill what the request leaves out.
variablesobject- Values for
{{name}}placeholders — HTML-escaped in the HTML body. replyTostring- Reply-To address.
headersobjectX-…headers andList-Unsubscribeonly, 20 at most.tagsobject- Up to 8 labels, letters, digits,
_and-. Shown in the log and sent with every event. attachmentsarray- Up to 10 files,
{ filename, content (base64), contentType? }, 10 MB in total. Executables are refused. scheduledAtstring- ISO 8601, up to 30 days ahead.
curl -X POST https://emailapi.mercestack.com/v1/email \
-H "Authorization: Bearer msk_live_…" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-1042-receipt" \
-d '{
"from": "Acme <[email protected]>",
"to": ["[email protected]"],
"template": "receipt",
"variables": { "order": "1042", "total": "$48.00" },
"tags": { "category": "receipt" },
"attachments": [
{ "filename": "receipt.pdf", "content": "JVBERi0xLjQK…" }
]
}'{
"id": "6f1c2a90-…",
"status": "sent",
"providerMessageId": "0100018f…"
}Send a batch
emailapi.mercestack.com/v1/email/batchUp to 100 messages in one request. If any message is invalid the whole batch is refused before anything is sent; otherwise each gets its own id and status, failures included. No attachments or schedule in a batch.
Body
emailsarrayrequired- 1–100 messages, each shaped like a single send.
const { batchId, data } = await email.emails.batch([
{ from: "[email protected]", to: "[email protected]", template: "welcome", variables: { name: "Ada" } },
{ from: "[email protected]", to: "[email protected]", template: "welcome", variables: { name: "Bo" } },
]);{
"batchId": "b7e1…",
"data": [
{ "id": "6f1c…", "status": "sent", "providerMessageId": "0100…" },
{ "id": "7a2d…", "status": "failed", "providerMessageId": null }
]
}Retrieve an email
emailapi.mercestack.com/v1/email/{id}The message, its recipients and every delivery report about it, oldest first.
const message = await email.emails.get("6f1c2a90-…");{
"id": "6f1c2a90-…",
"status": "delivered",
"recipients": { "to": ["[email protected]"], "cc": [], "bcc": [] },
"events": [
{ "type": "sent", "occurredAt": "2026-10-25T09:00:00.120Z" },
{ "type": "delivered", "recipient": "[email protected]",
"detail": { "smtpResponse": "250 2.0.0 OK" },
"occurredAt": "2026-10-25T09:00:01.300Z" }
]
}Cancel a scheduled email
emailapi.mercestack.com/v1/email/{id}Calls off a message that is still scheduled. Anything already sent answers 409.
await email.emails.cancel("6f1c2a90-…");{ "id": "6f1c2a90-…", "status": "cancelled" }