Kirim Email Transaksional dengan AWS Lambda + MailAnvil
AWS Lambda udah jadi tulang punggung backend serverless di Indonesia — dari API Gateway, event S3, sampai cron EventBridge. Tapi waktu harus kirim email transaksional (OTP, invoice, reset password), developer sering kena dua jebakan: konfigurasi SES yang ribet (verifikasi domain, pindah sandbox ke production, setup DKIM manual), atau narik nodemailer + SMTP yang nambah dependensi dan credential.
Padahal Lambda Node.js 18+ udah punya fetch global. MailAnvil itu REST API polos — berarti kamu cuma butuh satu fetch, tanpa aws-sdk, tanpa SES, tanpa SMTP.
Tutorial ini kasih fungsi Lambda paling bersih untuk kirim email transaksional.
Kenapa MailAnvil?
- Tanpa SES — satu endpoint REST, gak pusing sandbox/production SES
- Tanpa SMTP — gak perlu credential SMTP,
fetchnative aja - Harga Rupiah — gak kena markup kurs USD
- Bayar QRIS/GoPay — gak perlu kartu kredit internasional
- Deliverability terurus — DKIM/SPF ditangani, gak masuk spam
- Idempotency-Key — aman retry tanpa email duplikat
- Dokumentasi Bahasa Indonesia — contoh kode dalam konteks lokal
Prasyarat
- Runtime Node.js 18+ (punya
fetchglobal dannode:crypto) - Akun MailAnvil (daftar gratis di mailanvil.com)
- Domain terverifikasi di MailAnvil
Step 1: Simpan API Key sebagai Environment Variable
Jangan hardcode API key di kode. Taruh di Lambda environment variable (Console → Configuration → Environment variables, atau via SAM/CDK/Serverless Framework):
MAILANVIL_API_KEY = re_ganti_dengan_api_key_kamu
Kode bacanya lewat process.env.MAILANVIL_API_KEY.
Step 2: Satu Handler pakai fetch Native
// index.mjs — AWS Lambda, Node.js 18+
import { createHash } from 'node:crypto';
const ENDPOINT = 'https://api.mailanvil.com/v1/send';
const API_KEY = process.env.MAILANVIL_API_KEY;
function idempotencyKey(to, subject, html) {
return createHash('sha256')
.update(`${to}|${subject}|${html}`)
.digest('hex');
}
export async function handler(event) {
const { to, name } = JSON.parse(event.body ?? '{}');
const payload = {
from: '[email protected]',
to: [to],
subject: `Selamat Datang, ${name}!`,
html: `<h1>Halo, ${name}!</h1><p>Akun kamu siap kirim email.</p>`
};
const res = await fetch(ENDPOINT, {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
'Idempotency-Key': idempotencyKey(to, payload.subject, payload.html)
},
body: JSON.stringify(payload)
});
return {
statusCode: res.status,
body: JSON.stringify({ ok: res.status === 202, mailanvil: await res.json() })
};
}
Satu handler, satu fetch, tanpa require('aws-sdk'), tanpa nodemailer. 202 Accepted = email masuk antrian kirim.
Step 3: Kirim OTP Verifikasi
// Trigger dari API Gateway: POST /send-otp
export async function otpHandler(event) {
const { to, otp } = JSON.parse(event.body ?? '{}');
const html = '<div style="font-family: system-ui; background:#000; color:#fff; max-width:600px; margin:0 auto; padding:40px 20px;">'
+ '<h1 style="color:#ff801f;">Kode Verifikasi Kamu</h1>'
+ '<p>Gunakan kode berikut untuk verifikasi akun:</p>'
+ `<p style="font-size:32px; font-weight:700; letter-spacing:6px;">${otp}</p>`
+ '<p style="color:#666; font-size:14px;">Kode berlaku 5 menit.</p>'
+ '</div>';
const text = `Kode verifikasi kamu: ${otp} (berlaku 5 menit)`;
const res = await fetch(ENDPOINT, {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
'Idempotency-Key': idempotencyKey(to, 'Kode Verifikasi Akun', html)
},
body: JSON.stringify({
from: '[email protected]',
to: [to],
subject: 'Kode Verifikasi Akun',
html,
text
})
});
return { statusCode: res.status, body: JSON.stringify({ ok: res.status === 202 }) };
}
Step 4: Idempotency Key untuk Retry Aman
Lambda otomatis retry event yang gagal (timeout, exception) — bahkan sampai RetryAttempts kamu penuhi. Tanpa idempotency key, retry = email duplikat ke user.
Makanya key-nya deterministic: hash SHA-256 dari to|subject|html. Event yang sama → key sama → MailAnvil cuma kirim satu email.
Jangan pernah pake Date.now() atau crypto.randomUUID() sebagai idempotency key — tiap retry bakal kelihatan kayak email baru.
Production Tips
1. Naikkan Timeout
Default Lambda 3 detik — terlalu mepet buat cold start + network call. Set 10–15 detik biar aman. MailAnvil balas 202 cepat, tapi cold start bisa makan 1–2 detik sendiri.
2. Jangan Taruh di VPC Tanpa NAT
Kalau function di dalam VPC tanpa NAT Gateway, dia gak bisa akses internet → fetch ke MailAnvil timeout. Paling simpel: jangan masukin function ke VPC (kecuali kamu butuh akses RDS, dan itu pun tambah NAT).
3. Retry Cuma untuk Error Transient
Retry Lambda aman untuk network error / 5xx. Tapi kalau udah dapat 202, event-nya udah sukses — biarin idempotency key yang jaga duplikat, bukan retry manual.
4. Jangan Commit Secret
MAILANVIL_API_KEY wajib env var Lambda. Kalau pake SAM/CDK, ambil dari SSM Parameter Store / Secrets Manager, jangan hardcode di template.yaml.
Perbandingan dengan Approach Lain
| Approach | Dependency | DKIM/SPF | Harga | Bayar |
|---|---|---|---|---|
SES SDK (aws-sdk) |
aws-sdk + region + sandbox→prod | ⚠️ Manual (verifikasi + DKIM sendiri) | USD + per-region | Kartu kredit |
SMTP (nodemailer) |
nodemailer + credential SMTP | ⚠️ Manual | Bervariasi | Kartu kredit |
| MailAnvil REST | 0 (fetch native) |
✅ Otomatis | IDR | QRIS/GoPay |
Tanpa SDK, tanpa SES, tanpa SMTP — fetch native Node.js 18+ udah cukup. Satu handler, satu endpoint, jalan.
Kesimpulan
AWS Lambda + MailAnvil = cara paling bersih kirim email transaksional secara serverless di Indonesia. Kamu dapet:
- ✅ Zero dependency —
fetchnative, gak nambahaws-sdk/nodemailer - ✅ Tanpa SES — gak pusing sandbox, verifikasi, dan pindah production
- ✅ Deliverability otomatis — DKIM/SPF ditangani, gak masuk spam
- ✅ Idempotency key — aman dari retry Lambda tanpa email duplikat
- ✅ Harga Rupiah, bayar QRIS/GoPay — gak pusing kurs USD
Cocok buat OTP login, invoice e-commerce, notifikasi booking, dan event-driven notification lewat EventBridge/SQS.
Coba sendiri: daftar di mailanvil.com, verifikasi domain, set env var, dan deploy handler di atas dalam 5 menit.
Butuh API key? Daftar early access di mailanvil.com — gratis 500 email/bulan.