Skip to main content
Required permission: Sending → Write (messages:send) Sending is a separate permission from everything else. messages:write lets a key file and star mail that already exists; it does not let it send. Mail sent here leaves under your domain’s reputation and spends your plan’s daily allowance, so granting it is a deliberate choice.

Request

Address fields accept either an array or a comma-separated string. Both are common in the wild and neither is wrong.
from may be a mailbox or an alias. An alias sends as itself — that is what the recipient sees — while the mailbox behind it authenticates, files the copy in its Sent folder and carries the sending limits. List them with GET /v1/aliases.The limits key on the owning mailbox, never the alias. Otherwise one mailbox could multiply its own daily allowance by inventing addresses, which a catch-all makes free.Private mailboxes cannot send through the API at all: the message would have to be encrypted with a key only the owner’s browser holds.

Attachments

Each entry is filename, base64 content, and an optional content_type (defaults to application/octet-stream).
At most 10 attachments totalling 8 MB decoded. The ceiling leaves headroom under SES’s ~10 MB message limit once MIME encoding is added — base64 inflates content by roughly a third, and that inflation happens after this check.

Response

202 Accepted. The message has been handed to the mail server, which is not the same as delivered — remote servers accept and bounce on their own schedule.
A recipient in rejected was refused by the mail server outright — usually a malformed address. Recipients in accepted were taken for delivery. A copy is filed in the Sent folder automatically. If that filing fails the send still reports success: the message has already gone, and reporting failure would invite you to send it twice.

Limits

Sending passes several ceilings, and they fail differently: The per-mailbox limits are the ones that decide whether a leaked key can burn your domain’s reputation before you notice, so an API key does not get a more generous version of them than the web app has. The daily allowance is the entitlement your plan sells, and it is shared: messages sent from the dashboard and through the API draw on the same counter. rate_limited carries a Retry-After header. quota_exceeded does not — the allowance resets at midnight UTC.

Errors

See Errors for the full response shape.