Default mail configuration Laravel dibuat untuk development, bukan untuk production load. Ketika traffic meningkat, SMTP timeout, queue driver selection, dan retry policy menjadi faktor kritis yang menentukan apakah email sampai atau tidak. Artikel ini membahas konfigurasi mail driver Laravel yang production-ready untuk use case transaksional: OTP, invoice, notifikasi, dan alert.
Daftar Isi
Kenapa Default Mail Configuration Laravel Bukan untuk Production?
Jawaban singkat: default SMTP timeout 5 detik terlalu ketat untuk production environment.
Laravel ship dengan konfigurasi yang toleran untuk development. Di local, koneksi SMTP ke Mailhog atau Mailtrap hampir instant, latency di bawah 1ms. Tapi ketika Anda switch ke SMTP server yang nyata seperti KIRIM.EMAIL atau Gmail, latency jaringan nyata mulai bermain. Di Indonesia, latency ke server Singapore bisa 30-50ms, ke server US bisa 200ms+. Kalau koneksi SMTP timeout-nya cuma 5 detik, ketika server SMTP lagi load atau network jitter terjadi, email gagal kirim tanpa retry. User dapat error, Anda dapat support ticket.
Masalah kedua: default mail driver sync itu blocking. Setiap Mail::send() atau Mail::to() akan freeze request HTTP sampai email benar-benar terkirim atau timeout. Untuk email OTP yang harus sampai dalam 500ms agar user tidak close halaman sebelum kode arrive, ini disaster. Untuk invoice yang dikirim setelah payment confirmation, ini membuat user menunggu 3-5 detik untuk halaman success padahal proses lain sudah selesai.
Masalah ketiga yang sering tidak disadari: retry policy. Default queue retry di Laravel itu 3 kali, tapi tanpa configured delay. Retry pertama langsung setelah kegagalan, retry kedua langsung lagi. Kalau SMTP server memang sedang overloaded (bukan network issue), retry yang hampir simultan justru memperburuk kondisi server dan bisa menyebabkan temporary IP blacklist.
Jawaban untuk ketiga masalah ini ada di konfigurasi mail driver yang tepat untuk production environment.
Cara Pilih Mail Driver: Sync vs Queue untuk Setiap Use Case
Jawaban: sesuaikan dengan urgency dan volume email. Jangan pakai satu driver untuk semua use case.
Use case yang butuh sync atau queue sangat cepat:
- OTP verifikasi login: harus sampai sebelum user menutup halaman verifikasi
- Password reset: user sedang tunggu untuk klik link reset
- Order confirmation payment: user sedang di halaman sukses, butuh bukti transaksi
- Two-factor authentication code: user stuck di login page kalau email belum arrive
Use case yang bisa pakai queue standard:
- Invoice email: dikirim setelah payment confirmed, delay 1-2 detik masih acceptable
- Notifikasi newsletter: tidak ada urgency sama sekali
- Daily digest: batch job, delay menit bahkan jam tidak masalah
- Welcome email setelah registration: user sudah dapat welcome message di UI, email adalah backup
Untuk OTP dan password reset, Laravel menyediakan mail driver sync yang masih acceptable kalau volume rendah, yaitu di bawah 10 email per menit. Tapi begitu volume naik, switch ke queue dengan worker yang dedicated dan prioritized untuk high priority queue. Konfigurasinya:
// .env
MAIL_MAILER=smtp
MAIL_HOST=smtp.kirim.email
MAIL_PORT=587
MAIL_USERNAME=your-username
MAIL_PASSWORD=your-api-key
MAIL_ENCRYPTION=tls
MAIL_TIMEOUT=30
MAIL_READ_TIMEOUT=30
Timeout 30 detik bukan tanpa alasan. SMTP server yang properly configured akan merespon dalam 5-15 detik untuk email normal. Timeout 5 detik default Laravel terlalu ketat untuk jaringan dengan latency Indonesia ke server international. Kalau server SMTP queue 10 email dari antrean lain, response time bisa naik ke 8-12 detik. Dengan timeout 5 detik, email akan gagal di saat itu padahal sebenarnya server sehat.
Ada satu hal yang sering diabaikan: MAIL_FROM_ADDRESS. Banyak developer pakai email [email protected] yang tidak memiliki SPF record sendiri, atau pakai domain yang berbeda dari domain utama aplikasi. Email yang dikirim dari domain yang tidak punya SPF akan langsung masuk spam folder di Gmail dan Yahoo, tidak peduli seberapa bagus konfigurasi SMTP-nya. Selalu set MAIL_FROM_ADDRESS ke domain yang sudah Anda punya full control: SPF, DKIM, dan DMARC sudah configured.
Untuk use case yang tidak urgent, pakai queue:
// .env
MAIL_MAILER=queue
QUEUE_CONNECTION=database
Atau dengan Redis untuk performance yang lebih baik:
// .env
QUEUE_CONNECTION=redis
Driver queue menyimpan job email ke tabel atau Redis, worker proses secara async. Request HTTP langsung selesai, email dikirim oleh queue worker di background. Untuk aplikasi yang deploy di server Indonesia dan pakai KIRIM.EMAIL sebagai SMTP, latency dari worker ke SMTP server adalah sekitar 30-50ms, masih sangat manageable untuk queue processing.
Cara Setup Mail Queue dengan Database di Laravel 11
Jawaban: generate migration, migrate, set QUEUE_CONNECTION, dan jalankan worker. Tidak ada yang rumit kalau Anda tahu langkah-langkahnya.
Langkah pertama, generate tabel jobs:
php artisan queue:table
php artisan migrate
Ini membuat tabel jobs dan failed_jobs di database Anda. Kalau database Anda sudah direplikasi (misalnya read replica untuk query dan writer untuk insert), pastikan queue connection pointing ke database writer, bukan read replica. Queue jobs tulis ke database, dan routing ke read replica akan menyebabkan error “database locked” di high volume.
Kedua, set mail driver dan queue connection di .env:
MAIL_MAILER=queue
QUEUE_CONNECTION=database
Perlu diingat: mail driver queue di Laravel tidak berarti email langsung diproses async. Queue driver butuh worker process yang jalan terpisah dari web server. Kalau Anda jalankan php artisan serve tanpa worker, email akan stuck di jobs table sampai ada yang memanggil queue:work. Untuk development, kadang lebih mudah pakai driver sync agar bisa lihat error langsung. Di production, queue worker harus jalan terus.
Ketiga, ketika mengirim email, specify queue name kalau diperlukan:
Mail::to($user->email)->queue(new OrderConfirmation($order));
Atau untuk high-priority queue seperti OTP, specify queue name secara eksplisit:
Mail::to($user->email)->onQueue('high')->send(new OtpEmail($code));
Keempat, jalankan worker untuk queue high dan default secara terpisah:
# Terminal 1: worker untuk OTP (high priority)
php artisan queue:work redis --queue=high,default --tries=3
# Terminal 2: worker untuk email biasa
php artisan queue:work redis --queue=default --tries=3
Konfigurasi worker terpisah penting karena kalau queue high penuh, worker tidak akan starvation. Queue default tetap diproses tapi tidak blocking queue critical seperti OTP. Di Linux, gunakan Supervisor untuk manage worker process agar otomatis restart kalau crash:
# /etc/supervisor/conf.d/laravel-worker.conf
[program:laravel-worker-high]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/your-app/artisan queue:work redis --queue=high,default --tries=3 --sleep=3 --tries=3
autostart=true
autorestart=true
stopasgroup=true
numprocs=2
redirect_stderr=true
stdout_logfile=/var/www/your-app/storage/logs/worker.log
stopwaitsecs=3600
Dengan Supervisor, worker otomatis restart kalau crash, dan Anda bisa scale dengan ubah numprocs tanpa ubah configuration.
Untuk monitoring queue, Laravel menyediakan queue:failed dan queue:retry all commands. Di production, kombinasi ini dengan tool seperti Laravel Horizon memberikan visualisasi real-time dari queue jobs. Horizon menampilkan berapa job pending, failed, processed per minute, dan memory usage per worker. Untuk aplikasi dengan ribuan email per hari, Horizon adalah investasi yang worth it.
Bagaimana Handle Mail Failure dan Retry Otomatis?
Jawaban: mail queue sudah punya sistem retry built-in, yang perlu Anda lakukan adalah konfigurasi yang tepat dan monitoring yang konsisten.
Ketika email gagal dikirim melalui queue, Laravel otomatis retry berdasarkan konfigurasi --tries dan --delay. Default-nya 3 kali dengan jeda yang bisa Anda set:
php artisan queue:work redis \
--queue=high,default \
--tries=3 \
--backoff=10 \
--max-time=3600
--backoff=10 berarti retry kedua dilakukan 10 detik setelah kegagalan pertama, retry ketiga 10 detik lagi setelah kegagalan kedua. Untuk email transaksional, 3 tries dengan linear backoff kadang terlalu cepat. SMTP server yang sedang rate-limit akan butuh waktu untuk reset counter. Anda bisa set manual per mailable class dengan array backoff:
// app/Mail/OrderConfirmation.php
public $tries = 5;
public $backoff = [5, 15, 30, 60];
Ini berarti retry pertama setelah 5 detik, kedua setelah 15 detik, ketiga setelah 30 detik, keempat setelah 60 detik. Total maximum wait time sebelum email dianggap failed: sekitar 110 detik.
Kenapa tidak langsung pakai 5 tries dari awal? Karena setiap retry yang gagal ke SMTP server yang sedang masalah justru menambah load di server tersebut.algoritma backoff exponential yang lambat memberikan waktu bagi SMTP server untuk recover, tanpa membanjiri dengan retry yang tidak berguna.
Email yang sudah gagal 5 kali bisa di-inspect melalui failed_jobs table:
php artisan queue:failed
php artisan queue:retry 5 # retry job ID 5
php artisan queue:retry all # retry semua failed jobs
Untuk monitoring alert, buat custom command yang check failed_jobs count dan kirim alert kalau exceeds threshold. Threshold yang reasonable untuk awal: 10 failed jobs dalam 1 jam. Tidak perlu alert untuk 1-2 failure, tapi kalau sampai 10, kemungkinan ada problem sistemik:
// app/Console/Commands/AlertFailedEmails.php
protected $signature = 'emails:check-failed {--threshold=10}';
protected $description = 'Check failed email jobs and send alert if over threshold';
public function handle()
{
$count = DB::table('failed_jobs')->count();
if ($count > $this->option('threshold')) {
Mail::to('[email protected]')->send(
new FailedEmailsAlert($count)
);
}
}
Schedule dengan Laravel Scheduler agar berjalan otomatis:
// app/Console/Kernel.php
protected function schedule(Schedule $schedule)
{
$schedule->command('emails:check-failed --threshold=10')->hourly();
}
Jangan lupa untuk schedule cleanup failed jobs yang sudah old, karena tabel ini akan terus grow dan consume storage:
$schedule->command('queue:flush')->daily();
Kenapa Email Laravel Masuk Spam Walau SMTP Sudah Benar?
Jawaban: karena configuration SMTP yang benar itu hanya satu faktor dari banyak faktor deliverability yang saling terkait.
Banyak developer sudah setup SPF, DKIM, DMARC dengan benar tapi email tetap masuk spam. Biasanya masalahnya ada di empat area yang sering tidak disadari:
1. SMTP connection dari IP yang punya reputasi buruk.
Shared hosting server yang sama dengan spammer akan punya IP reputation yang contaminated. Email dari IP yang pernah dipurple oleh spammer akan masuk spam folder sebelum konten email dibaca, karena spam filter memeriksa IP reputation terlebih dahulu. KIRIM.EMAIL menggunakan Managed IP untuk setiap akun, reputation yang selalu di-maintain setiap saat.
2. Email content yang triggering spam filter.
Panjang email, rasio text-to-image, penggunaan kata-kata tertentu, dan missing List-Unsubscribe header bisa menyebabkan spam classification. Email transaksional tetap harus punya List-Unsubscribe header kalau dikirim dalam volume tinggi, karena tanpa header ini spam complaint rate naik. Rekomendasi: selalu tambahkan List-Unsubscribe header ke email transaksional, bahkan kalau Anda tidak mengirim marketing email.
3. Volume spike yang tidak natural.
Kirim 10 email per hari selama sebulan, lalu tiba-tiba kirim 5.000 email dalam satu jam. Email provider akan flag ini sebagai suspicious activity dan bisa temporary block atau throttle sender. Ini terjadi karena spam filter belajar dari volume pattern. Email provider expecting gradual ramp-up, bukan instant spike. KIRIM.EMAIL sendiri menangani ini dengan automatic throttling yang menyesuaikan kecepatan kirim berdasarkan reputation score secara gradual.
4. Missing List-Unsubscribe header.
Email transaksional tetap butuh List-Unsubscribe header kalau email dikirim dalam volume tinggi. Tanpa header ini, spam complaint rate naik karena penerima tidak punya cara mudah untuk unsubscribe dan sebagai gantinya akan mark as spam.
Cara kerja mail queue vs mail send di Laravel sudah pernah kami bahas sebelumnya. Kombinasi queue yang properly configured dengan SMTP server yang punya IP reputation bersih adalah fondasi deliverability yang solid. Fondasi yang kuat akan lebih resilient terhadap perubahan temporary di salah satu faktor.
Checklist Konfigurasi Mail Driver Production-Ready
Berikut checklist konfigurasi mail yang perlu Anda review sebelum deployment. Kalau Anda belum pernah cek salah satu dari ini, segera cek sebelum aplikasi Anda kirim email ke production users.
SMTP Configuration:
- Timeout minimal 30 detik, bukan 5 detik default
- Encryption TLS di port 587 (STARTTLS), bukan SSL port 465 unless server specifically requires it
- Username dan password bukan email/password login, tapi API key dari SMTP provider
- MAIL_FROM_ADDRESS set ke domain yang sama dengan SPF/DKIM/DMARC yang sudah configured
- Pertimbangkan untuk set MAIL_FROM_NAME ke nama sender yang recognizable supaya penerima trust email Anda
Queue Configuration:
- QUEUE_CONNECTION=redis atau database, bukan sync
- Worker restart interval –backpack atau –max-time set untuk auto-reload config changes
- Failed jobs table dimonitor dengan daily check
- Separate worker untuk high-priority queue (OTP, password reset)
- Set flag –memory pada worker untuk prevent memory leak yang crash worker di scale
- Run worker dengan Supervisor untuk auto-restart on failure
Monitoring:
- Alert kalau failed_jobs count exceeds threshold (recommend: 10 per hour)
- Metric: email sent per minute, bounce rate, spam complaint rate
- Log semua email yang gagal dengan full error message termasuk SMTP response codes untuk debugging
- Implement heartbeat untuk queue workers: kalau tidak ada job yang diproses dalam 5 menit, alert on-call team Anda
- Schedule
queue:flushdaily untuk prevent failed_jobs table from growing unbounded
FAQ
Kapan harus pakai mail driver sync dan kapan pakai queue di Laravel?
Pakai sync untuk email yang harus sampai immediately seperti OTP dan password reset, tapi hanya kalau volume rendah, di bawah 10 email per menit. Untuk volume lebih tinggi atau email yang tidak urgent seperti invoice, pakai queue dengan worker yang running di background.
Bagaimana cara setup mail queue dengan database di Laravel 11?
Jalankan php artisan queue:table untuk generate migration, php artisan migrate untuk buat tabel jobs, set MAIL_MAILER=queue dan QUEUE_CONNECTION=database di .env, lalu jalankan php artisan queue:work untuk proses queue. Detailnya ada di section Cara Setup Mail Queue di atas.
Kenapa email Laravel masuk spam padahal SMTP sudah benar?
Karena SPF, DKIM, DMARC yang benar hanyalah satu faktor.IP reputation dari server yang kirim, email content yang triggering spam filter, volume spike yang tidak natural, dan missing List-Unsubscribe header juga menentukan apakah email masuk inbox atau spam folder.
Apa bedanya mail driver SMTP dan mailgun atau postmark di Laravel?
Driver SMTP menggunakan SMTP server eksternal seperti KIRIM.EMAIL, SendGrid, atau Gmail. Driver mailgun, postmark, dan ses menggunakan API masing-masing provider. Driver SMTP lebih universal dan compatible dengan SMTP server manapun, sementara API driver punya fitur tambahan dari provider tapi less portable.
Berapa timeout yang wajar untuk SMTP di environment production?
Minimal 30 detik. Default Laravel 5 detik terlalu ketat untuk jaringan dengan latency Indonesia ke server international. Timeout yang terlalu pendek akan menyebabkan email gagal kirim padahal SMTP server dalam kondisi sehat.
Bagaimana cara handle mail failure dan retry otomatis di Laravel?
Queue driver Laravel sudah punya built-in retry system. Set jumlah retry dengan public $tries = 5 di mailable class, set backoff delay dengan public $backoff = [5, 15, 30, 60], dan monitor failed jobs table secara regular dengan schedule daily check.
Kalau Anda butuh SMTP server yang: (1) punya timeout lebih longgar dari default provider lain, (2) menyediakan dashboard monitoring untuk track email status, dan (3) dengan server located di Indonesia untuk latency rendah ke aplikasi deployed di Indonesia, KIRIM.EMAIL Dev menyediakan infrastructure email delivery yang dibuat untuk developer Indonesia.
Hasbi Putra adalah Head of Marketing di KIRIM.EMAIL, email delivery infrastructure untuk developer dan tim IT di Indonesia. KIRIM.EMAIL mengirim lebih dari 11 juta email per hari dengan server yang sepenuhnya berlokasi di Indonesia.
