Errors and limits
The API answers with the usual HTTP status codes. An error has a JSON body that says why, with two exceptions: a 404 has no body, and neither has a 400 for a body that is not JSON or has a field of the wrong type (a string where a list belongs, say). A method or a content type that a path does not take answers 404 too; send JSON with Content-Type: application/json.
Status codes
| Status | Body | When |
|---|---|---|
200, 201, 202, 204 | the result (none for 204) | success; 202 means accepted, the work happens afterwards |
400 | validation problem | a field is not valid; the body lists the fields |
401 | {"error": "invalid_api_key"} | no key, or a key that does not exist or was revoked |
403 | {"error": "…"} | insufficient_scope or client_ip_not_allowed, see Authentication |
404 | none | no such resource in this key's project and mode, or no such path |
409 | {"error": "…"} | conflicts with what is there, see the codes below |
422 | {"error": "…"} | valid, but cannot be done now, see the codes below |
429 | {"error": "…"} | a limit; wait as long as the Retry-After header says (in seconds) |
500 | problem with a traceId | an error at Postilio; quote the traceId when you contact support |
503 | {"error": "dns_unavailable"} | only from a domain check: DNS gave no answer |
Validation problems
A 400 is application/problem+json with the problems per field:
{
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"errors": {
"to": ["Between 1 and 50 recipients are required."],
"body": ["Either text or html is required."]
},
"traceId": "00-4d6a1c9b71484cc59ac852cda603b93c-28de36d1c118bc08-00"
}
The keys of errors are the request's field names; body stands for text and html together, and idempotencyKey for the Idempotency-Key header. Fix the request before you send it again: the same request gets the same answer.
404, never 403, for what is not yours
A resource of another project answers 404, just like one that does not exist, so ids cannot be probed. The same goes for the other mode: a test key does not find live messages, and a live key does not find test messages.
Error codes
| Status | error | Meaning |
|---|---|---|
401 | invalid_api_key | the key is missing, unknown or revoked |
403 | insufficient_scope | the key lacks the scope of this call |
403 | client_ip_not_allowed | the key may not be used from this address |
409 | idempotency_key_reused_with_different_request | the Idempotency-Key was used for another request in the last 24 hours |
409 | domain_exists | the project has this domain already |
409 | address_already_suppressed | the address is on the suppression list already |
409 | webhook_endpoint_limit_reached | the project has 10 webhook endpoints |
409 | delivery_still_pending | the delivery is still being retried |
409 | endpoint_paused | resume the webhook endpoint first |
422 | unverified_sender_domain | the sender's domain is not verified, or has been failing for over 72 hours |
422 | sender_domain_not_allowed_for_key | the key is restricted to other sending domains |
422 | sandbox_recipient_not_allowed | in the sandbox: a recipient outside your team and verified domains |
422 | reason_required | removing a complaint from the suppression list needs a reason |
429 | sandbox_daily_limit_reached | in the sandbox: the day's recipients are used up |
429 | sandbox_rate_limit_reached | in the sandbox: this minute's recipients are used up |
429 | too_many_checks | a domain can be checked once a minute |
503 | dns_unavailable | the domain check got no answer from DNS |
Handle a code you do not know by its status code.
The sandbox
A new organization starts in the sandbox. By default its live mail:
- goes only to the organization's active members and to addresses on the verified domains of its projects. A message with any other recipient answers
422 sandbox_recipient_not_allowed, and nothing of it is sent; - is limited to 100 recipients per day (UTC) and 10 recipients per minute, for the whole organization, through the API and SMTP together. Over a limit the answer is
429withsandbox_daily_limit_reachedorsandbox_rate_limit_reached, and aRetry-Afteruntil the next UTC day or minute. A message that is refused uses up nothing.
Test keys are never limited by the sandbox. The Sandbox page in the portal shows your organization's limits, the day's usage and how to ask for full access, which lifts them.
Limits
| What | Limit |
|---|---|
| Recipients per message | 50 |
| Attachments | 20, at most 10 MB together; size times recipients at most 25 MB |
| Subject | 998 characters |
| Tag | 64 characters: letters, digits, -, _ |
Idempotency-Key | 1 to 256 characters, remembered for 24 hours |
| Sandbox (live mail) | 100 recipients a day, 10 a minute, per organization (by default) |
| Domain check on request | once a minute per domain |
| Webhook endpoints | 10 per project |
| API key restrictions | 20 domains, 20 networks |
List pages (limit) | 1 to 100, 50 by default |
| SMTP | 10 MB per message, 20 messages per connection, 600 messages per key per minute (see SMTP) |