Kirim Email Invoice Otomatis dengan MailAnvil + Laravel — Panduan Lengkap untuk Startup SaaS Indonesia
Kirim Email Invoice Otomatis dengan MailAnvil + Laravel
Setiap platform invoicing di Indonesia — dari Jurnal.id, Paper.id, sampai Mekari — punya satu kesamaan: mereka harus kirim invoice lewat email, cepat, dan nggak boleh nyangkut di spam.
Tapi ada masalah: API email internasional seperti SendGrid dan Resend punya tiga kelemahan buat developer Indonesia:
- Harga dalam USD — Rp 149rb MailAnvil Starter vs Rp 330rb+ SendGrid untuk 10K email/bulan
- Pembayaran ribet — nggak support QRIS atau GoPay
- Latency tinggi — server di US/Eropa, bukan di edge Asia Tenggara
MailAnvil berjalan di Cloudflare Workers (edge delivery, ~80ms dari Jakarta) dan menerima pembayaran QRIS. Di tutorial ini, saya tunjukkan cara kirim email invoice dari aplikasi Laravel dalam 15 menit.
Kenapa Laravel?
Laravel adalah framework PHP paling populer di Indonesia. Data dari Stack Overflow 2026 menunjukkan 43% developer backend Indonesia pakai Laravel. Kalau kamu sedang bangun:
- Platform invoicing SaaS seperti Paper.id
- Sistem billing untuk marketplace
- Aplikasi akuntansi UMKM
- Portal pembayaran SPP sekolah
...maka integrasi email transaksional adalah fitur wajib.
Step 1: Daftar MailAnvil dan Dapatkan API Key
Buka mailanvil.com, daftar gratis. Setelah verifikasi email, kamu dapat:
- 500 email gratis per bulan (cukup untuk development dan testing)
- API key langsung aktif
- Dashboard untuk monitoring delivery
Simpan API key-mu. Jangan commit ke repository.
Step 2: Setup Project Laravel
composer create-project laravel/laravel invoice-app
cd invoice-app
Simpan API key di .env
MAILANVIL_API_KEY=ma_key_xxxxxxxxxxxxxxxx
MAILANVIL_API_URL=https://api.mailanvil.com/v1
Tambahkan ke config/services.php:
'mailanvil' => [
'api_key' => env('MAILANVIL_API_KEY'),
'api_url' => env('MAILANVIL_API_URL', 'https://api.mailanvil.com/v1'),
],
Step 3: Buat MailAnvil Service Class
Buat file app/Services/MailAnvilService.php:
<?php
namespace App\Services;
use Illuminate\Support\Facades\Http;
use Illuminate\Http\Client\RequestException;
class MailAnvilService
{
private string $apiKey;
private string $apiUrl;
public function __construct()
{
$this->apiKey = config('services.mailanvil.api_key');
$this->apiUrl = config('services.mailanvil.api_url');
}
/**
* Kirim email via MailAnvil API.
*
* @return array{id: string, status: string}
* @throws RequestException
*/
public function send(array $data): array
{
$response = Http::withToken($this->apiKey)
->withHeaders([
'Content-Type' => 'application/json',
'Idempotency-Key' => $data['idempotency_key'] ?? uniqid('em_', true),
])
->post("{$this->apiUrl}/send", [
'from' => $data['from'],
'to' => $data['to'],
'subject' => $data['subject'],
'html' => $data['html'],
'text' => $data['text'] ?? strip_tags($data['html']),
'reply_to' => $data['reply_to'] ?? null,
])
->throw()
->json();
return [
'id' => $response['id'],
'status' => $response['status'],
];
}
}
Poin penting:
- Idempotency-Key mencegah email terkirim dua kali kalau terjadi retry
- Selalu sertakan text versi selain html — anti-spam best practice
- throw() otomatis lempar exception kalau API return error
Step 4: Buat InvoiceMail Mailable
Biar tetap pakai pola Laravel yang familiar, kita bungkus di Mailable:
<?php
namespace App\Mail;
use App\Services\MailAnvilService;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class InvoiceMail extends Mailable
{
use Queueable, SerializesModels;
public function __construct(
public array $invoice,
) {}
public function send($mailer)
{
$service = app(MailAnvilService::class);
$html = view('emails.invoice', ['invoice' => $this->invoice])->render();
$text = "Invoice #{$this->invoice['number']}\n"
. "Total: Rp " . number_format($this->invoice['total'], 0, ',', '.') . "\n"
. "Jatuh tempo: {$this->invoice['due_date']}\n"
. "Bayar di: {$this->invoice['payment_url']}";
return $service->send([
'from' => 'billing@perusahaanmu.com',
'to' => [$this->invoice['customer_email']],
'subject' => "Invoice #{$this->invoice['number']} — " . config('app.name'),
'html' => $html,
'text' => $text,
'reply_to' => 'support@perusahaanmu.com',
]);
}
}
Step 5: Template Email Invoice
Buat resources/views/emails/invoice.blade.php:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
body { font-family: -apple-system, BlinkMacSystemFont, sans-serif; color: #1a1a1a; }
.container { max-width: 600px; margin: 0 auto; padding: 24px; }
.header { background: #ff801f; color: #fff; padding: 24px; border-radius: 8px 8px 0 0; }
.body { background: #fafafa; padding: 24px; border: 1px solid #e5e5e5; }
.total { font-size: 24px; font-weight: bold; color: #ff801f; margin: 16px 0; }
.cta { display: inline-block; background: #ff801f; color: #fff; padding: 12px 32px;
border-radius: 6px; text-decoration: none; font-weight: 600; margin: 16px 0; }
.footer { color: #888; font-size: 13px; margin-top: 24px; text-align: center; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1 style="margin:0">Invoice #{{ $invoice['number'] }}</h1>
</div>
<div class="body">
<p>Halo {{ $invoice['customer_name'] }},</p>
<p>Terima kasih atas pesanan Anda. Berikut detail invoice:</p>
<table style="width:100%; border-collapse:collapse; margin:16px 0">
@foreach($invoice['items'] as $item)
<tr style="border-bottom:1px solid #e5e5e5">
<td style="padding:8px 0">{{ $item['description'] }}</td>
<td style="text-align:right">Rp {{ number_format($item['amount'], 0, ',', '.') }}</td>
</tr>
@endforeach
</table>
<div class="total">
Total: Rp {{ number_format($invoice['total'], 0, ',', '.') }}
</div>
<p>Jatuh tempo: <strong>{{ $invoice['due_date'] }}</strong></p>
<a href="{{ $invoice['payment_url'] }}" class="cta">Bayar Sekarang</a>
<p style="margin-top:24px; color:#666">Pembayaran bisa via transfer bank, QRIS, GoPay, atau kartu kredit.</p>
</div>
<div class="footer">
<p>{{ config('app.name') }} — {{ config('app.url') }}</p>
<p>Email ini dikirim otomatis. Butuh bantuan? Balas email ini atau hubungi support@perusahaanmu.com</p>
</div>
</div>
</body>
</html>
Step 6: Panggil dari Controller / Queue Job
<?php
use App\Mail\InvoiceMail;
use Illuminate\Support\Facades\Mail;
// Contoh: setelah user checkout / generate invoice
$invoice = [
'number' => 'INV-2026-0781',
'customer_name' => 'Budi Santoso',
'customer_email' => 'budi@tokosejahtera.com',
'total' => 1250000,
'due_date' => '2026-08-03',
'payment_url' => 'https://bayar.perusahaanmu.com/inv/INV-2026-0781',
'items' => [
['description' => 'Paket Pro — Bulanan (Jul 2026)', 'amount' => 1250000],
],
];
Mail::to($invoice['customer_email'])->send(new InvoiceMail($invoice));
Kalau volume email tinggi, dispatch ke queue job biar nggak blocking response:
use App\Jobs\SendInvoiceEmail;
SendInvoiceEmail::dispatch($invoice)->onQueue('emails');
Monitoring & Debugging
Dashboard MailAnvil (app.mailanvil.com) tampilkan:
- Status per email: queued → sent → delivered / bounced
- Reason kalau bounce (invalid address, mailbox full, spam)
- Daily volume vs kuota
Tips debugging:
- Email nyangkut di spam? Pastikan domain-mu sudah verified DKIM & SPF (MailAnvil auto-handle DKIM kalau DNS di Cloudflare)
- API return 403? Cek domain
fromsudah verified di dashboard - Rate limit? Free plan 500/bulan. Upgrade ke Starter (Rp 149rb) untuk 10K/bulan
Kenapa MailAnvil Cocok untuk Startup Indonesia
Tiga hal yang bikin MailAnvil berbeda:
| MailAnvil | SendGrid | Resend | |
|---|---|---|---|
| Harga 10K email | Rp 149rb/bln | Rp 330rb+/bln | Rp 300rb+/bln |
| Pembayaran | QRIS, GoPay, transfer ✅ | Kartu kredit aja | Kartu kredit aja |
| Support | Bahasa Indonesia | Inggris | Inggris |
| Latency Jakarta | ~80ms (CF edge) | ~400ms (US) | ~300ms (US) |
| MCP native | ✅ AI agents langsung pakai | ❌ | ✅ (official) |
Mulai Gratis
Nggak perlu kartu kredit. Daftar di mailanvil.com, dapat 500 email gratis per bulan. Cukup untuk testing dan development.
Untuk production: Rp 149rb/bulan buat 10K email. Itu 55% lebih murah dari SendGrid.
Tutorial sudah selesai. Kalau ada pertanyaan, mention @mailanvil di X atau kirim email ke support@mailanvil.com.
Next: "Kirim Email Notifikasi Real-Time dengan MailAnvil + Golang untuk Backend High-Performance"