Limits
Every limit here is a real number enforced by the API, not a guideline.
Requests
| Limit | Value |
|---|---|
| Requests per minute, per API key | 120 |
| Request body, including base64 attachments | 6 MB |
| Recipients per batch send | 500 |
Over the per-minute limit returns 429 rate_limited. The limit is per key, so splitting genuinely separate workloads across separate keys also separates their limits — and is better practice anyway, because scopes and revocation then apply independently.
Attachments
| Limit | Value |
|---|---|
| Files per message | 20 |
| Per file, accepted by the schema | 10 MB |
| What actually governs | the 6 MB total body cap |
Attachments are base64-encoded inside the JSON body, which adds about a third to their size. So roughly 4 MB of real files fits in a 6 MB body. A single 10 MB file will never fit, despite the per-file schema limit.
Over the cap returns 413 attachments_too_large or 413 payload_too_large, with the actual and permitted byte counts in the message.
If you are near the limit, host the file and send a link. It is also better for delivery — large attachments are a spam signal, and many corporate mail servers strip or reject them.
Sending volume
Your monthly send allowance and daily cap depend on your plan. See Pricing for the current figures, and your workspace for what you have used this month.
Volume limits are separate from the per-minute rate limit above. You can be inside your monthly allowance and still be rate-limited for sending too fast in one minute.
Retention
| Data | Kept |
|---|---|
| Email log | 30 days |
Rows older than that are gone, not archived. If you need longer, store the events yourself — see Email log.
Fields
| Field | Limit |
|---|---|
subject | 2,000 characters |
templateId | 64 characters, lowercase slug |
category | 64 characters, lowercase slug |
idempotencyKey | 200 characters |
Control characters and line separators are rejected in any field that becomes a mail header. That is what stops a crafted subject line forging extra headers.