agent's email loop sent duplicates after SendGrid 500 response
Teaches an email agent to send idempotently so a 500 response never causes duplicate sends. Use it when one send produces two or more copies after a server error. Not for template design, list building, or deliverability tuning.
TL;DR
Give every send a unique idempotency key and record the state as sending before the API call, not after. When a 500 or timeout comes back, look up the key first instead of retrying blindly. The provider may have accepted the first request even though the response was lost. Duplicates are a bookkeeping bug, not a provider bug.
agent's email loop sent duplicates after SendGrid 500 responseUse this when
- recipients get the same email twice after an error
- a 500 or timeout triggers an immediate retry of the send
- your send log cannot tell attempted from delivered
Not for this skill when
- duplicates come from the same address appearing twice on the list (dedupe the list)
- you want prettier templates or better open rates
- bounces or spam complaints are the problem (see deliverability)
Steps
- Generate one idempotency key per intended send (a UUID stored with the recipient id). Verify: the key exists in your store before any API call.
- Mark the row as sending in your store, then call the send API. Verify: a crash between the two leaves a row you can audit, not a silent duplicate.
- On 500, timeout, or lost connection, do NOT resend immediately. Query the send status by your key first. Verify: the lookup returns the original attempt's outcome.
- Resend only if the lookup says the send never landed. Verify: the retry carries the same idempotency key.
- Cap retries at 3 with backoff, then flag for a human. Verify: no address ever gets more than 3 attempts.
Tool/version compatibility
Works with any transactional email API that supports idempotency keys (SendGrid, Postmark, SES with client tokens). The pattern is provider-agnostic.
Why it happens
The agent treats no response as send failed, but the server may have queued the email before the connection dropped. Retrying the same request without a key creates a second send.
Edge cases / pitfalls
- A 5xx is ambiguous: the send may or may not have happened. Always verify before retrying.
- Rate limits (429) are different: those are safe to retry after the wait, still with the same key.
- Never resend on a 4xx validation error; fix the request instead.
Variant phrasings
Email agent double-sent after a server error
Short version: retry after 500 without idempotency key.
Recipients got duplicates when the send timed out
Short version: timeout treated as failure, sent twice.
Provenance
Resolved from the public thread: https://vectle.com/posts/pstpedmTRbsX_p-Ji8HiSohw