Kirim Email Transaksional dengan PHP + MailAnvil
PHP masih raja web Indonesia. Dari WordPress, cPanel shared hosting, sampai backend CodeIgniter — sebagian besar situs lokal jalan di atas PHP. Tapi waktu harus kirim email transaksional (OTP, invoice, reset password, konfirmasi order), banyak developer masih pake mail() bawaan atau PHPMailer + SMTP Gmail/SendGrid.
Masalahnya: mail() sering masuk spam (tanpa DKIM/SPF), PHPMailer nambah dependensi Composer, dan SMTP eksternal butuh credential + harga USD kena markup kurs.
Tutorial ini kasih cara paling bersih kirim email dari PHP — pakai MailAnvil REST API lewat cURL bawaan PHP. Tanpa Composer, tanpa library tambahan, jalan di shared hosting manapun.
Kenapa MailAnvil?
- Tanpa SMTP — REST API satu endpoint, gak perlu credential SMTP
- 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
- PHP 7.4+ dengan ekstensi
curl(aktif default di hampir semua hosting) - Akun MailAnvil (daftar gratis di mailanvil.com)
- Domain terverifikasi di MailAnvil
Cek curl aktif:
php -r "var_dump(extension_loaded('curl'));"
Step 1: Simpan API Key
Jangan hardcode API key di kode. Taruh di env / di luar webroot:
// config.php (di luar document root, atau set via .env)
putenv('MAILANVIL_API_KEY=re_ganti_dengan_api_key_kamu');
Di shared hosting cPanel, set lewat .htaccess:
SetEnv MAILANVIL_API_KEY "re_ganti_dengan_api_key_kamu"
Lalu baca pakai getenv().
Step 2: Satu Fungsi kirimEmail() pakai cURL
<?php
// mailanvil.php — satu file, satu tanggung jawab
function kirimEmail(string $to, string $subject, string $html, string $text = ''): array
{
$payload = [
'from' => '[email protected]',
'to' => [$to],
'subject' => $subject,
'html' => $html,
'text' => $text,
];
$ch = curl_init('https://api.mailanvil.com/v1/send');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('MAILANVIL_API_KEY'),
'Content-Type: application/json',
'Idempotency-Key: ' . uniqid('email-', true),
],
CURLOPT_POSTFIELDS => json_encode($payload),
CURLOPT_TIMEOUT => 15,
]);
$body = curl_exec($ch);
$status = (int) curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
$err = curl_error($ch);
curl_close($ch);
if ($err) {
return ['ok' => false, 'status' => 0, 'error' => $err];
}
return [
'ok' => $status === 202, // 202 Accepted = sukses
'status' => $status,
'body' => json_decode($body, true),
];
}
Satu fungsi, dipakai di seluruh app. curl bawaan PHP — gak perlu composer require phpmailer/phpmailer.
Step 3: Kirim OTP Verifikasi
<?php
require 'mailanvil.php';
function kirimOtp(string $to, string $otp): array
{
$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;">' . htmlspecialchars($otp) . '</p>'
. '<p style="color:#666; font-size:14px;">Kode berlaku 5 menit.</p>'
. '</div>';
$text = "Kode verifikasi kamu: $otp (berlaku 5 menit)";
return kirimEmail($to, 'Kode Verifikasi Akun', $html, $text);
}
// Contoh pemakaian
$result = kirimOtp('[email protected]', '482915');
if ($result['ok']) {
echo "OTP terkirim.\n";
} else {
error_log('Gagal kirim email: ' . json_encode($result));
}
Step 4: Idempotency Key untuk Retry Aman
Idempotency-Key bikin email yang sama gak terkirim dua kali kalau kamu retry (timeout, crash). Masalahnya, uniqid() di atas bikin key baru tiap call — retry jadi key beda. Buat key deterministic berdasarkan konten:
<?php
function kirimEmailAman(string $to, string $subject, string $html, string $text = ''): array
{
$idempotencyKey = hash('sha256', $to . '|' . $subject . '|' . $html);
$payload = [
'from' => '[email protected]',
'to' => [$to],
'subject' => $subject,
'html' => $html,
'text' => $text,
];
$ch = curl_init('https://api.mailanvil.com/v1/send');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('MAILANVIL_API_KEY'),
'Content-Type: application/json',
'Idempotency-Key: ' . $idempotencyKey,
],
CURLOPT_POSTFIELDS => json_encode($payload),
CURLOPT_TIMEOUT => 15,
]);
$body = curl_exec($ch);
$status = (int) curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);
return ['ok' => $status === 202, 'status' => $status, 'body' => json_decode($body, true)];
}
Sekarang retry pakai key yang sama → MailAnvil cuma kirim satu email. Jangan retry email yang udah 202 (sukses diterima).
Production Tips
1. Selalu Cek curl_error()
Kalau koneksi gagal (DNS, timeout), curl_exec() balikin false. Jangan langsung json_decode — cek error dulu seperti contoh di atas.
2. Retry untuk Transient Error
Retry aman untuk 5xx dan network error. JANGAN retry kalau udah dapat 202 — idempotency key udah jagain duplikat.
<?php
$result = kirimEmailAman($to, $subject, $html, $text);
$retryable = !$result['ok'] && ($result['status'] >= 500 || $result['status'] === 0);
if ($retryable) {
$result = kirimEmailAman($to, $subject, $html, $text); // satu retry
}
3. Jangan Commit Secret
MAILANVIL_API_KEY wajib env var / .htaccess, bukan di file yang ke-commit ke Git. Kalau pake GitHub, taruh .env di .gitignore.
4. Queue untuk Volume Tinggi
Untuk 1000+ email/jam, jangan kirim synchronous di request web. Pindah ke queue (Laravel queue, cron job, atau worker) biar response tetap cepat.
Perbandingan dengan Approach Lain
| Approach | Dependency | DKIM/SPF | Harga | Bayar |
|---|---|---|---|---|
mail() bawaan |
0 | ❌ Manual, sering spam | Gratis tapi nyasar spam | — |
| PHPMailer + SMTP Gmail | Composer + credential | ⚠️ Terbatas | Gratis (limit 500/hr) | — |
| SendGrid/SES SDK | Composer + akun | ✅ | USD + kurs | Kartu kredit |
| MailAnvil REST | 0 (cURL bawaan) | ✅ Otomatis | IDR | QRIS/GoPay |
Tanpa Composer, tanpa SMTP credential, tanpa SDK — cURL bawaan PHP udah cukup. Satu fungsi, satu endpoint, jalan.
Kesimpulan
PHP + MailAnvil = kombinasi paling simpel buat email transaksional di Indonesia. Kamu dapet:
- ✅ Zero dependency —
curlbawaan PHP, gak nambah Composer - ✅ Tanpa SMTP — REST API, gak pusing credential SMTP
- ✅ Deliverability otomatis — DKIM/SPF ditangani, gak masuk spam
- ✅ Idempotency key — aman retry tanpa email duplikat
- ✅ Harga Rupiah, bayar QRIS/GoPay — gak pusing kurs USD
Cocok buat WordPress plugin, backend CodeIgniter/Laravel, shared hosting cPanel, dan startup yang butuh OTP/invoice/notifikasi.
Coba sendiri: daftar di mailanvil.com, verifikasi domain, dan jalankan contoh kode di atas dalam 5 menit.
Butuh API key? Daftar early access di mailanvil.com — gratis 500 email/bulan.