Errors

The full vocabulary of the codes, and which ones are worth retrying.

Every failure has an HTTP status and a stable code. The status says whose problem it is, the code says which one, and together they say whether retrying makes any sense.

Status code What happened Retry
429 RATE_LIMITED over 60 sends a minute per key yes, after Retry-After
502 SMTP_DELIVERY_FAILED the SMTP server does not answer or rejects temporarily yes
503 none, HTML body pigeon unreachable, almost always a deploy yes
504 none the proxy closed the wait yes
502 SMTP_DELIVERY_REJECTED the SMTP server rejected it for good no
409 IDEMPOTENCY_IN_PROGRESS a send with the same Idempotency-Key is still running yes, in a few seconds
409 SMTP_AUTH_FAILED the SMTP credentials of the project were rejected no
409 SMTP_NOT_CONFIGURED, SMTP_INCOMPLETE, SMTP_CREDENTIALS_MISSING the project is not configured to send no
400 VALIDATION_ERROR, INVALID_JSON, PROJECT_ID_MISMATCH the request is wrong no
401 INVALID_API_KEY, UNAUTHENTICATED key missing, revoked or invalid no
403 FORBIDDEN_ORIGIN the call comes from a browser no
404 TEMPLATE_NOT_FOUND, PROJECT_NOT_FOUND the template does not exist or is not yours no
413 FILE_TOO_LARGE attachments over the limit no
415 UNSUPPORTED_MEDIA_TYPE unexpected Content-Type no
500 INTERNAL_ERROR a failure of pigeon no

The two 502s are not the same thing

SMTP_DELIVERY_FAILED is the mail server unreachable, a timeout, or a temporary rejection of the protocol (the SMTP 4xx: greylisting, mailbox full for the moment, service unavailable). The same email, sent a few seconds later, may go out.

SMTP_DELIVERY_REJECTED is a final rejection (the SMTP 5xx: recipient does not exist, message refused). Retrying it only produces more failed rows, and what needs fixing is the address or the content.

A 500 is not retried because it is a failure of pigeon: if it comes back, it comes back the same. A 503 is, and it is by far the most frequent case, because it is the window in which the container is replaced by a deploy.

IDEMPOTENCY_IN_PROGRESS is the only 409 worth retrying: it says that another attempt with your own key is talking to the mail server right now, and the outcome is not known yet. The other 409s are configuration to fix.

The id survives the failure

On a delivery failure, details.emailId carries the id of the row that was recorded. It is what lets you find the attempt again in the panel, and it is worth saving next to your own record: it turns a report into something verifiable instead of a guess.