← Back to all posts
2026-08-31 · MailAnvil Team

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?

Prasyarat

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:

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.