Kirim Email Transaksional dari Cloudflare Workers dengan MailAnvil + Hono
Startup Indonesia makin banyak deploy di Cloudflare Workers — latency Jakarta di bawah 10ms, scale otomatis, nggak kelola server. Tapi begitu butuh kirim email transaksional, banyak yang balik ke solusi lama: spin VPS, install nodemailer, pusing SMTP relay.
Nggak perlu. Kalau backend kamu di edge, email juga harus dari edge. Tutorial ini bangun endpoint kirim email pakai Hono + MailAnvil, langsung jalan di Cloudflare Workers.
Kenapa MailAnvil untuk Workers?
MailAnvil sendiri dibangun di atas CF Workers. Satu ekosistem, satu mental model.
| MailAnvil | Resend | SendGrid | |
|---|---|---|---|
| Harga 10K email | Rp 149rb/bln | ~Rp 320rb | ~Rp 319rb |
| Pembayaran | QRIS, GoPay | Kartu kredit | Kartu kredit |
| Docs | Bahasa + English | English | English |
| Runtime | CF Workers native | Node SDK | Node SDK |
| AI agent | MCP-native | Ada | Ada |
Untuk tim yang udah di ekosistem Cloudflare, MailAnvil nggak maksa kamu pindah stack. API-nya REST biasa, bisa dipanggil dari worker manapun.
Yang Kita Bangun
Flow minimal:
POST /send-email → Hono Worker (edge Jakarta) → MailAnvil /v1/send → inbox user
User request masuk ke worker terdekat, email keluar dari region yang sama. Nggak ada hop ke AWS us-east-1.
Step 1: Setup Project Hono
npm create hono@latest mailanvil-worker
cd mailanvil-worker
npm install
Step 2: Secret API Key
Simpan key sebagai secret Workers (jangan hardcode):
npx wrangler secret put MAILANVIL_API_KEY
Step 3: Email Sender
src/email.ts:
const BASE = 'https://api.mailanvil.com/v1';
export async function sendEmail(payload: {
to: string;
subject: string;
html: string;
text: string;
idempotencyKey?: string;
}) {
const res = await fetch(`${BASE}/send`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${process.env.MAILANVIL_API_KEY}`,
...(payload.idempotencyKey ? { 'Idempotency-Key': payload.idempotencyKey } : {}),
},
body: JSON.stringify({
from: '[email protected]',
to: [payload.to],
subject: payload.subject,
html: payload.html,
text: payload.text,
}),
});
if (res.status === 202) return res.json();
const err = await res.json();
throw new Error(err.error?.message || `MailAnvil ${res.status}`);
}
Step 4: Route Handler
src/index.ts:
import { Hono } from 'hono';
import { sendEmail } from './email';
const app = new Hono();
app.post('/send-otp', async (c) => {
const { email, otp } = await c.req.json();
if (!email || !otp) return c.json({ error: 'email dan otp wajib' }, 400);
try {
await sendEmail({
to: email,
subject: 'Kode Verifikasi Kamu',
html: `<h1 style="color:#ff801f">Kode OTP: <strong>${otp}</strong></h1>`,
text: `Kode OTP kamu: ${otp}`,
idempotencyKey: `${email}-${Date.now()}`,
});
return c.json({ success: true });
} catch (e) {
return c.json({ error: 'Gagal kirim OTP' }, 500);
}
});
export default app;
Step 5: Deploy & Test
npx wrangler deploy
curl -X POST https://mailanvil-worker.namakamu.workers.dev/send-otp \
-H "Content-Type: application/json" \
-d '{"email":"[email protected]","otp":"482913"}'
Response {"success":true}. Email masuk dalam <1 detik dari region Jakarta.
Use Case Nyata di Indonesia
Pola yang sama dipakai tiga skenario paling umum:
- Fintech OTP — DANA, OVO, dan dompet digital lain kirim OTP via email sebagai fallback SMS. Latency edge = OTP nggak expired sebelum sampai.
- Travel booking — Tiket.com dan platform travel kirim e-ticket + konfirmasi booking. Semakin cepat email keluar, semakin kecil chance user cancel.
- Food delivery invoice — GoFood/GrabFood merchant kirim struk digital + estimasi antar. Volume tinggi, butuh harga per-email murah.
Semua lewat satu endpoint: POST /v1/send.
Best Practices
- Idempotency-Key wajib. Workers bisa retry request saat timeout. Tanpa key, user dapat email dobel.
- Secret, bukan env publik. Pakai
wrangler secret put, jangan commit key ke repo. - Verifikasi domain dulu. DKIM wajib biar email nggak masuk spam. MailAnvil auto-setup DKIM buat domain di Cloudflare.
- Pantau bounce. Kill switch otomatis aktif kalau bounce >5%. Jaga reputasi domain.
Mulai Gratis
Free plan 500 email/bulan, tanpa kartu kredit. Pembayaran QRIS/GoPay. Docs Bahasa Indonesia lengkap.