Limits
Where a limit exists for a non-obvious reason, the reason is written down. Guessing at a cap is how you discover it in production.
Message size
| Limit | Value | Why |
|---|---|---|
| Attachments per message | 10 MB total | Isolate memory, see below |
| Attachment count | 20 | Practical |
| Total message | 40 MB | Upstream provider ceiling |
| Subject | 998 characters | RFC 5322 line length |
| Custom headers | 20, 2 KB each | Receiver tolerance |
Why 10 MB and not 40
Attachments arrive base64-encoded inside a JSON body, which inflates them by a third. That body becomes a UTF-16 string when parsed, doubling it again, and is copied once more while the message is assembled. Ten megabytes of attachment is therefore already sixty to eighty megabytes of peak memory in a request isolate capped at 128 MB.
Raising this needs a streaming upload path, not a larger constant. For anything bigger, host the file and send a link — recipients’ mail servers frequently reject large attachments anyway.
Recipients
| Limit | Value |
|---|---|
Recipients per message (to + cc + bcc) | 50 |
| Messages per batch request | 100 |
| Scheduled delivery horizon | 30 days |
Transactional only
Fifty recipients is a limit, not a target. This is a transactional API: mail triggered by a user action, addressed to one person. Fan-out to a list is a campaign, it will be detected as one, and it will get your organization paused.
Send limits
There are two, and a send has to satisfy both: a daily limit that resets at 00:00 UTC, and a monthly limit that resets on the 1st. New organizations start at 100 per day and 3,000 per month.
Both are counted in recipients, not messages. One send to fifty people costs fifty, because that is what it costs in reputation and in money. A request that would cross either line is refused whole and consumes nothing — you never end up with half a batch sent.
The month exists because a daily cap alone bounds very little: an account can spend it every single day, so the real ceiling on a leaked key was thirty times the number anyone approved. Exceeding the day returns daily_quota_exceeded, the month monthly_quota_exceeded, both with a 429.
Limits are raised as you accumulate history with a bounce rate under 2% and a complaint rate under 0.1%.
Idempotency
Idempotency-Key is remembered for 24 hours, scoped to your organization, and at most 255 characters. The request body is hashed alongside it: reusing a key with different content returns 409 rather than replaying the first response, because silently discarding the second email would be worse than an error.
Webhooks
| Limit | Value |
|---|---|
| Delivery timeout | 10 seconds |
| Retry schedule | 1m, 5m, 30m, 2h, 6h, 24h |
| Auto-disable threshold | 20 consecutive failures |
| Signature tolerance | 5 minutes |
A 4xx other than 429 ends the retry ladder immediately: your endpoint understood the request and refused it, so repeating it for a day helps nobody.