Setelah bermain dengan file storage di episode sebelumnya, kali ini saya belajar tentang sesuatu yang hampir semua aplikasi web butuhkan: mengirim email. Notifikasi pendaftaran, reset password, invoice, newsletter — semua itu dikirim lewat email. Di Laravel, proses ini ternyata jauh lebih rapi daripada sekadar pakai mail() PHP native. Saya baru tahu bahwa Laravel punya konsep Mailable yang membuat setiap email jadi seperti “surat terstruktur” — ada alamat, isi, bahkan lampiran.
Mengapa Tidak Langsung Pakai mail() PHP?
Saya sempat berpikir: “PHP sudah punya mail(), kenapa perlu Mailable?” jawabannya sederhana — mail() itu seperti menulis surat tanpa amplop: bisa, tapi ribet. Kamu harus handle header, MIME type, boundary, dan encoding manual. Belum lagi kalau mau kirim HTML + plain text sekaligus, atau lampiran file.
Laravel Mailable menyelesaikan semua itu. Setiap email didefinisikan sebagai satu class yang bisa di-read seperti novel — isi apa yang dikirim, ke siapa, dengan format apa. Saya suka cara ini karena kodenya jadi jelas dan mudah diuji.
Membuat Mailable Pertama
Gunakan Artisan untuk membuat Mailable:
php artisan make:mail WelcomeEmail
Artisan akan membuat file app/Mail/WelcomeEmail.php. Di dalamnya ada dua method utama:
__construct()— tempat menerima data (misalnya objek User) yang akan ditampilkan di email.build()— method untuk “menghias” email: pilih template Blade, set subjek, lampirkan file, dll.
Berikut contoh Mailable sederhana untuk mengirim email selamat datang:
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class WelcomeEmail extends Mailable
{
use Queueable, SerializesModels;
public $user;
public function __construct($user)
{
$this->user = $user;
}
public function build()
{
return $this->subject('Selamat Datang di Aplikasi Kami!')
->view('emails.welcome');
}
}Perhatikan public $user — properti public di Mailable otomatis tersedia di Blade view. Jadi di resources/views/emails/welcome.blade.php, saya bisa langsung pakai {{ $user->name }}. Ini yang membuat Mailable terasa natural — datanya mengalir dari constructor ke view tanpa boilerplate berlebih.
Template Email dengan Blade
Email HTML sebaiknya pakai table-based layout karena klien email (Outlook, Gmail) punya CSS engine yang terbatas. Tapi untuk awal, saya mulai dengan yang sederhana dulu:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto;">
<h2 style="color: #333;">Halo, {{ $user->name }}!</h2>
<p>Selamat datang di aplikasi kami. Akun Anda sudah aktif.</p>
<p style="color: #666;">Salam hangat,<br>Tim {{ config('app.name') }}</p>
</body>
</html>Saya juga bisa pakai layout master-child seperti Blade biasa. Cukup tambahkan @extends('layouts.email') di atas template — ini berguna kalau semua email punya header/footer yang sama.
Mengirim Email
Mengirim email di Laravel sesederhana ini:
use App\Mail\WelcomeEmail; use Illuminate\Support\Facades\Mail; Mail::to($user->email)->send(new WelcomeEmail($user));
Tapi ini mengirim email secara synchronus — artinya request HTTP harus menunggu email selesai dikirim. Kalau server mail lambat atau sedang down, user akan menunggu lama. Inilah mengapa Laravel punya konsep queued email.
Queue Email agar Tidak Lambat
Cukup tambahkan ShouldQueue interface pada Mailable, maka email akan dikirim secara asynchronous:
use Illuminate\Contracts\Queue\ShouldQueue;
class WelcomeEmail extends Mailable implements ShouldQueue
{
// ... sisanya sama
}Sekarang saat Mail::to(...)->send(...) dipanggil, Laravel tidak langsung mengirim email — melainkan memasukkannya ke queue. Worker queue akan mengambil dan mengirimnya di background. Request HTTP langsung selesai, user tidak menunggu.
Untuk ini berfungsi, saya perlu mengatur driver queue di .env:
QUEUE_CONNECTION=database # atau redis, sqs, dll.
Jika pakai database, jangan lupa jalankan migration untuk tabel jobs: php artisan queue:table lalu php artisan migrate. Kalau pakai Redis, cukup pastikan Redis berjalan — tidak perlu migration tambahan.
Notification: Lebih dari Sekadar Email
Di sini saya baru menyadari sesuatu yang menarik: di Laravel, email hanyalah salah satu channel notifikasi. Laravel punya sistem Notification yang bisa mengirim pesan lewat email, database, SMS, bahkan Slack — semua dari satu definisi yang sama.
Bayangkan seperti ini: kamu menulis satu “pengumuman” (notification), lalu memilih “alat pengiriman” (channel). Beda alat, isi pesan tetap sama, hanya formatnya menyesuaikan.
php artisan make:notification AccountActivated
Di dalam app/Notifications/AccountActivated.php, saya mengatur channel apa saja yang didukung:
public function via($notifiable)
{
return ['mail', 'database'];
}Dan method terpisah untuk format masing-masing channel:
public function toMail($notifiable)
{
return (new MailMessage)
->subject('Akun Aktif!')
->line('Akun Anda sudah aktif.')
->line('Selamat menggunakan aplikasi kami.');
}
public function toArray($notifiable)
{
return [
'message' => 'Akun Anda sudah aktif.',
];
}Saat dikirim, Laravel akan otomatis mengirim email DAN menyimpan ke database sesuai channel yang dipilih. Saya tinggal pakai:
$user->notify(new AccountActivated());
Sistem notifikasi ini sangat powerful. Kalau besok saya mau tambah channel Slack, cukup tambah 'slack' di array via() dan buat method toSlack() — kode kirim email tidak berubah sama sekali. Ini prinsip open-closed principle yang diterapkan dengan sangat elegan.
Database Notification: Notifikasi In-App
Channel 'database' menyimpan notifikasi ke tabel notifications. Untuk mengaktifkannya, jalankan:
php artisan notifications:table php artisan migrate
Setelah itu, user bisa melihat notifikasi di halaman dashboard. Laravel otomatis menyediakan route /notifications kalau menggunakan Breeze atau Jetstream. Cukup panggil Auth::user()->unreadNotifications untuk mendapatkan notifikasi yang belum dibaca — ini sangat praktis untuk fitur lonceng notifikasi (notification bell) di UI.
Konfigurasi Mail di .env
Sebelum email bisa terkirim, saya perlu mengatur driver mail di .env. Laravel mendukung banyak driver:
| Driver | Cocok untuk | Catatan |
|---|---|---|
smtp | Produksi | Paling umum; Gmail, Mailgun, SendGrid |
mailgun | Produksi | Paketet email transactional populer |
log | Development | Email ditulis ke log file, tidak benar-benar terkirim |
array | Testing | Email ditampung di array, bisa di-assert di unit test |
Saat development, saya pakai MAIL_DRIVER=log — email tidak benar-benar terkirim, tapi isinya bisa dilihat di storage/logs/laravel.log. Ini menyelamatkan saya dari kesalahan kirim email asli ke alamat yang salah saat testing.
Lampiran File di Email
Mengirim lampiran juga mudah. Di method build(), tambahkan attach():
public function build()
{
return $this->subject('Invoice Anda')
->view('emails.invoice')
->attach(storage_path('app/invoices/invoice-001.pdf'), [
'as' => 'invoice.pdf',
'mime' => 'application/pdf',
]);
}Bahkan bisa melampirkan file dari storage disk tertentu dengan attachFromStorage(). Ini sangat berguna kalau file invoice tersimpan di S3 — tidak perlu download dulu ke lokal untuk melampirkannya.
Poin Penting yang Saya Catat
- Mailable = email sebagai class. Readable, testable, maintainable. Jauh lebih rapi dari
mail()native. - ShouldQueue = jangan biarkan user menunggu email terkirim. Pasang interface ini di Mailable untuk async sending.
- Notification = abstraksi di atas email. Satu notifikasi bisa ke email + database + Slack sekaligus.
- Database notification = notifikasi in-app yang tersimpan di tabel. Cocok untuk fitur bell notification.
- Driver mail di
.env: pakailogsaat development,smtp/mailgunsaat produksi - Lampiran mudah via
attach()atauattachFromStorage().
Topik ini mengajarkan saya bahwa Laravel tidak hanya memikirkan “bagaimana mengirim email”, tapi juga “bagaimana mengelola komunikasi dengan user secara menyeluruh.” Dari satu Mailable, bisa berkembang menjadi sistem notifikasi multi-channel yang elegan.
Komentar Terbaru