I Built an Email API for Indonesian Devs on Cloudflare Workers
I Built an Email API for Indonesian Devs on Cloudflare Workers
Every Indonesian developer has felt the pain. You build a SaaS, a booking system, a marketplace. You need transactional email — receipts, OTPs, booking confirmations. You go to Resend, SendGrid, Mailgun. And then the reality hits:
- USD pricing — $10/mo becomes Rp 160rb after bank fees and FX
- No QRIS — you need a foreign credit card
- English-only docs — technical but not native
- No local invoicing — your buku kas is crying
I built MailAnvil to fix this.
The Stack
Cloudflare Workers + AWS SES. Here's why:
- Workers — 10M requests/mo for $5. No cold starts, 330 edge locations.
- D1 — SQLite at the edge. $3/mo for 10GB.
- Durable Objects — per-key rate limiting with atomic counters. Unique to CF.
- SES — $10 per 100k emails. Same backend Resend uses.
Total infra cost at 100k emails/mo: ~$12. At 1M: ~$117. SES is 93% of the cost — CF stays negligible at any scale.
Architecture
Browser (Pages) → API Worker (Hono) → Queue → Consumer → SES
↑ SNS (bounce/complaint)
└→ Suppression list + Kill switch
The dashboard is a static SPA. Every operation (send email, manage domains, create API keys) hits the Worker. No framework. No SSR. Just HTML/JS that talks to the API.
Key Design Decisions
IDR pricing + QRIS/GoPay. Xendit or Midtrans for local payments. Paddle for USD. Indonesian devs pay in Rupiah via QRIS, GoPay, OVO, or bank transfer. Foreign devs pay by card.
Bahasa docs and support. Error messages, quickstart guides, and support hours in Indonesian. Not just translated — written for the local context.
MCP-native. An MCP server ships with the product. Claude Code, Cursor, and Codex discover send_email, get_email_status, list_templates automatically. AI agents can send emails without reading docs.
Invariants that protect the shared SES account. Every email API is only as good as its deliverability. Our invariants are non-negotiable:
- DKIM verification required before any send (no shared onboarding domain)
- Global suppression list checked at enqueue AND before SES call
- Claim-before-send pattern for at-most-once delivery
- Automated kill switches per customer (0.3% complaint or 5% hard-bounce triggers auto-pause)
- Rate limiting via Durable Objects (not eventually-consistent KV counters)
Why Not Just Use Resend?
Resend is excellent. They ship an official MCP server, great DX, fast API. But:
| Factor | Resend | MailAnvil |
|---|---|---|
| IDR pricing | ❌ | ✅ |
| QRIS/GoPay | ❌ | ✅ |
| Bahasa docs | ❌ | ✅ |
| Local invoicing | ❌ | ✅ |
| MCP server | ✅ | ✅ |
| $0 start | 3k/mo | 500/mo |
Resend served me well. But I kept wanting: "what if I could pay in Rupiah?" "What if the error messages were in Bahasa?" "What if my customers could pay via QRIS?"
So I built it.
What's Next
- Production access approval from AWS SES (pending 🤞)
- Deploy Workers to production
- Open beta
I'm building in public. Follow @mailanvil for updates.
Built on Cloudflare Workers + AWS SES. Open source at github.com/richaferry/mailanvil.