← Back to all posts
2026-09-14 · MailAnvil Team

Kirim Email Transaksional di Laravel dengan Mailanvil API — Tutorial Lengkap

Laravel punya driver mail bawaan untuk SMTP, SendGrid, dan Mailgun. Tapi kalau startup kamu butuh email API yang murah, bayar pakai QRIS, dan dukungannya dalam Bahasa Indonesia — Mailanvil jawabannya.

Tutorial ini cover: setup Laravel + Mailanvil API kirim email OTP, invoice booking, dan welcome email.

Kenapa Mailanvil untuk Laravel?

Fitur Mailanvil SendGrid Mailgun
Harga Gratis 500/bulan, Starter Rp 149rb $20/mo (100K) $35/mo (50K)
Pembayaran QRIS, GoPay, Xendit Kartu kredit USD Kartu kredit USD
MCP Support ✅ Native
Bahasa Docs Indonesia English English
Latency (ID) Edge via Cloudflare Singapore US East

Use case nyata di Indonesia: - Travel booking — kirim itinerary + e-ticket setelah pembayaran - Food delivery — invoice + struk ke customer - Fintech — OTP verifikasi akun + notifikasi transaksi

Langkah 1: Daftar & Dapatkan API Key

# Signup via API
curl -X POST https://api.mailanvil.com/v1/signup \
  -H "Content-Type: application/json" \
  -d '{"email":"[email protected]","password":"securepass123"}'

Response:

{
  "id": "cus_01HXYZ1234567890",
  "api_key": "key_xxxxxxxxxxxxxxxxxxxxxxxx"
}

Simpan api_key di file .env Laravel:

MAILANVIL_API_KEY=key_xxxxxxxxxxxxxxxxxxxxxxxx

Langkah 2: Tambahkan Domain di Mailanvil

Sebelum kirim email, domain harus terverifikasi DKIM:

curl -X POST https://api.mailanvil.com/v1/domains \
  -H "Authorization: Bearer $MAILANVIL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"startupmu.com"}'

Mailanvil akan return DNS records yang perlu kamu tambahkan di Cloudflare/Domain registrar.

Langkah 3: Buat Mail Service Provider Custom di Laravel

Laravel tidak punya driver bawaan untuk Mailanvil, tapi kita bisa pakai Illuminate\Mail\MailManager dengan custom transport. Cara paling bersih: buat HTTP client langsung.

Buat file app/Services/MailanvilService.php:

<?php

namespace App\Services;

use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;

class MailanvilService
{
    private string $apiKey;
    private string $baseUrl = 'https://api.mailanvil.com/v1';

    public function __construct()
    {
        $this->apiKey = config('services.mailanvil.api_key');
    }

    /**
     * Kirim email transaksional via Mailanvil API
     */
    public function send(array $params): array
    {
        $payload = [
            'from'    => $params['from'] ?? config('mailanvil.from_address'),
            'to'      => (array) $params['to'],
            'subject' => $params['subject'],
        ];

        // Support HTML + plain text
        if (isset($params['html'])) {
            $payload['html'] = $params['html'];
        }
        if (isset($params['text'])) {
            $payload['text'] = $params['text'];
        }

        // Optional: cc, bcc, replyTo
        if (isset($params['cc'])) {
            $payload['cc'] = (array) $params['cc'];
        }
        if (isset($params['bcc'])) {
            $payload['bcc'] = (array) $params['bcc'];
        }
        if (isset($params['reply_to'])) {
            $payload['replyTo'] = $params['reply_to'];
        }

        $response = Http::withHeaders([
            'Authorization' => 'Bearer ' . $this->apiKey,
            'Content-Type'  => 'application/json',
        ])->post("{$this->baseUrl}/send", $payload);

        if ($response->successful()) {
            return [
                'success'  => true,
                'email_id' => $response->json('id'),
                'status'   => $response->json('status'),
            ];
        }

        Log::error('MailAnvil send failed', [
            'status' => $response->status(),
            'error'  => $response->json('error'),
        ]);

        return [
            'success' => false,
            'error'   => $response->json('error.message', 'Unknown error'),
        ];
    }
}

Langkah 4: Konfigurasi di config/services.php

Tambahkan di config/services.php:

'mailanvil' => [
    'api_key'     => env('MAILANVIL_API_KEY'),
    'from_address' => env('MAILANVIL_FROM_ADDRESS', '[email protected]'),
],

Langkah 5: Kirim Email OTP — Fintech Use Case

Kirim OTP 6 digit ke nomor/email user:

<?php

namespace App\Jobs;

use App\Services\MailanvilService;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Support\Str;

class SendOtpEmail implements ShouldQueue
{
    use Queueable;

    public function __construct(
        private string $email,
        private string $otpCode
    ) {}

    public function handle(MailanvilService $mailanvil): void
    {
        $html = view('emails.otp', [
            'code'  => $this->otpCode,
            'email' => $this->email,
        ])->render();

        $mailanvil->send([
            'to'      => $this->email,
            'subject' => 'Kode Verifikasi Akun Anda',
            'html'    => $html,
            'text'    => "Kode verifikasi Anda: {$this->otpCode}. Berlaku 5 menit.",
        ]);
    }
}

Template Blade resources/views/emails/otp.blade.php:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <style>
    body { background: #000; color: #fff; font-family: system-ui, sans-serif; }
    .container { max-width: 560px; margin: 0 auto; padding: 40px 24px; }
    .code { font-size: 48px; font-weight: 700; color: #ff801f; text-align: center; 
            letter-spacing: 12px; padding: 32px 0; }
    .footer { color: #666; font-size: 13px; margin-top: 32px; }
  </style>
</head>
<body>
  <div class="container">
    <h1>Verifikasi Akun</h1>
    <p>Halo,</p>
    <p>Masukkan kode berikut untuk verifikasi akun <strong>{{ $email }}</strong>:</p>
    <div class="code">{{ $code }}</div>
    <p>Kode ini berlaku selama <strong>5 menit</strong>. Jangan bagikan kode ini ke siapapun.</p>
    <div class="footer">
      <p>Email ini dikirim oleh MailAnvil untuk startupmu.com</p>
    </div>
  </div>
</body>
</html>

Langkah 6: Invoice Email — Travel Booking

Kirim invoice + itinerary setelah pembayaran travel:

<?php

namespace App\Services;

class TravelInvoiceService
{
    public function __construct(
        private MailanvilService $mailanvil
    ) {}

    public function sendBookingConfirmation(array $booking): array
    {
        $html = view('emails.booking-confirmation', [
            'booking_id' => $booking['id'],
            'customer'   => $booking['customer_name'],
            'destination'=> $booking['destination'],
            'check_in'   => $booking['check_in'],
            'check_out'  => $booking['check_out'],
            'amount'     => number_format($booking['amount'], 0, ',', '.'),
        ])->render();

        return $this->mailanvil->send([
            'to'      => $booking['customer_email'],
            'subject' => "Booking Confirmed — {$booking['destination']}",
            'html'    => $html,
        ]);
    }
}

Gunakan di controller:

// app/Http/Controllers/BookingController.php

public function store(BookingRequest $request, TravelInvoiceService $invoice)
{
    $booking = Booking::create($request->validated());

    // Kirim email async via queue
    SendBookingEmail::dispatch($booking);

    return response()->json([
        'message' => 'Booking berhasil, email dikirim',
        'booking' => $booking->id,
    ], 201);
}

Langkah 7: Monitoring via Dashboard

Login ke app.mailanvil.com untuk monitor: - Status setiap email (queued, sent, delivered, bounced) - Statistik harian - Domain verification status - API key management

Ringkasan

Langkah Aksi
1 Daftar Mailanvil, dapat API key
2 Verifikasi domain (DNS records)
3 Buat MailanvilService.php
4 Tambah config di services.php
5 Kirim OTP/email transaksional
6 Monitor di dashboard

Harga: Free 500 email/bulan, Starter Rp 149rb/bulan untuk 10K email.

Coba sekarang: mailanvil.com


Tags: email API Indonesia, kirim email Laravel, transactional email murah, API email lokal, Laravel mail API, email OTP, fintech email