Inside a Reliable Email Pipeline: Queues, Retries, and Why "Accepted" Isn't "Delivered"
The most dangerous line in an email integration is the one that treats an HTTP 202 as the end of the story. Your API returned 202 Accepted — the email is queued, not delivered. What happens between that response and the inbox is where every reliable transactional email system lives or dies.
The moment after 202
When a booking confirmation leaves your app, it does not fly straight to the recipient. A well-built email API does four things before it ever talks to a mail server:
- Validate and enqueue — the send endpoint returns
202immediately and drops the message into a queue. This is deliberate: your API request should never block on SMTP round-trips. - Claim, don't race — a consumer worker claims the job with an atomic
UPDATE ... WHERE status='queued'. If zero rows update, another worker already got it. This is how you guarantee at-most-once delivery — no duplicate booking emails because two workers grabbed the same job. - Classify failures — a throttling error (
429, 5xx) is retried with backoff. A permanent rejection (bad address,4xxfrom the provider) is not retried — it goes straight to a dead-letter queue. Retrying a permanently bad address is how you burn your sender reputation. - Report honestly —
queued → sent → delivered / bounced / complainedper recipient, pushed to you via webhook.
That last step matters more than most teams think. "Sent" only means SES (or your provider) accepted it. Only the delivery/bounce webhook tells you the truth.
Why Indonesia makes this harder
Transactional email in Indonesia fails for three predictable reasons, and each maps to a pipeline decision:
- OTP for fintech (GoPay, OVO, DANA). A one-time code has a ~5-minute useful life. If your queue backs up during a traffic spike — payday, a promo — the OTP arrives after it expired. You need backpressure: a queue that sheds load gracefully instead of silently delaying time-sensitive mail.
- Food delivery invoices (GoFood, GrabFood, ShopeeFood). Every order fires a receipt at the exact moment the rider accepts it — thousands of near-simultaneous sends around lunch. Your rate limiter must be per-API-key, not a shared counter, or one noisy customer throttles everyone else.
- Travel booking confirmations (Traveloka, Tiket.com, Pegipegi). These are high-stakes — a missed confirmation means a customer shows up with no booking. They cannot be lost, so at-most-once delivery must be paired with idempotency keys: retrying the same request from your side must never produce a second email.
The queue is the product
When you evaluate an email API, don't ask "does it send mail." Ask what happens between enqueue and deliver:
- Is the send call async (returns
202, processes later) or does it block your request? - Are retries classified — throttling retried, permanent failures dead-lettered — or does it blindly retry everything?
- Is there an idempotency mechanism so your retries don't double-send?
- Do you get per-recipient delivery/bounce webhooks, or just a single ambiguous "sent"?
A flat, synchronous "send email" endpoint is fine at 500 emails a month. It collapses at 100,000 — which is exactly where most Indonesian startups are headed.
Pricing that doesn't punish scale
Pipeline reliability is table stakes. The other half is cost. International providers meter in USD — at 100,000 emails you're paying roughly $40 (≈ Rp 640rb) a month with Resend or SendGrid, and the FX conversion swings with the dollar. MailAnvil prices flat in Rupiah: Growth tier is Rp 599rb for 100,000 emails, and you pay with QRIS or GoPay — no card, no FX spread.
Built on AWS SES and Cloudflare Workers at the edge, MailAnvil gives you the queue, the classified retries, the per-recipient webhooks, and the IDR pricing in one API — plus Bahasa documentation and Bahasa support.
Try MailAnvil free at mailanvil.com.