Konfigurasi mail sudah beres di chapter sebelumnya; sekarang saatnya menekan tombol kirim. Laravel menyediakan facade Mail dengan dua gaya pengiriman: closure-based untuk email kilat satu-baris, dan pendekatan berbasis class (Mailable) untuk email yang lebih terstruktur — kita bahas yang pertama di sini. Karena sandbox memakai MAIL_MAILER=log, setiap email yang “terkirim” meninggalkan jejak penuh di storage/logs/laravel.log — header, penerima, subject, sampai isi pesan. Jejak itulah alat bukti kita sepanjang chapter: bukan klaim “sudah terkirim”, melainkan potongan log nyata yang bisa dibaca ulang.

Email Kilat dengan Mail::raw #

Untuk pesan teks sederhana — kode verifikasi, notifikasi singkat — Mail::raw() adalah jalur tercepat. Method ini menerima isi pesan mentah dan sebuah closure yang mengatur amplop pesan:

php
use Illuminate\Support\Facades\Mail;

Mail::raw('Pesanan Anda sedang diproses.', function ($message) {
    $message->to('[email protected]')
        ->subject('Status Pesanan #123');
});

Closure menerima objek $message bertipe Illuminate\Mail\Message. Rantai ->to()->subject() mengisi header tujuan dan judul email sebelum pesan diserahkan ke transport. Setelah baris ini dijalankan di sandbox, kita membuka storage/logs/laravel.log:

Output yang Dihasilkan:

text
[2026-10-13 19:25:16] local.DEBUG: From: Laravel <[email protected]>
To: [email protected]
Subject: Status Pesanan #123
MIME-Version: 1.0
Date: Tue, 13 Oct 2026 19:25:16 +0000
Message-ID: <[email protected]>
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable

Pesanan Anda sedang diproses.

Enam baris pertama adalah header MIME yang disusun Symfony Mailer di balik layar. Perhatikan baris From: Laravel <[email protected]> — nilainya diambil otomatis dari konfigurasi mail.from global karena kita tidak menyetel pengirim secara eksplisit. Baris Content-Type: text/plain menegaskan Mail::raw() mengirim teks polos tanpa HTML. Bentuk arrow function juga valid untuk closure pendek:

php
Mail::raw('Kode verifikasi Anda: 991177', fn ($message) => $message
    ->to('[email protected]')
    ->subject('Kode Verifikasi')
);

Isi Email dari View Blade #

Teks mentah cepat kaku begitu email perlu format. Mail::send() menerima nama view plus array data, sama seperti view() di controller. Kita buat dulu template di resources/views/emails/sapaan.blade.php:

blade
Halo {{ $nama }},

Terima kasih sudah berbelanja di toko kita.

Salam,
Toko Latihan

Lalu kirim view tersebut dengan data nama:

php
Mail::send('emails.sapaan', ['nama' => 'Budi'], function ($message) {
    $message->to('[email protected]', 'Budi')
        ->cc('[email protected]')
        ->bcc('[email protected]')
        ->replyTo('[email protected]')
        ->subject('Terima kasih atas pesanan Anda');
});

Argument kedua (['nama' => 'Budi']) tersedia sebagai variabel $nama di dalam view. Closure amplop kini menunjukkan header tambahan: to() dengan nama tampilan, cc() untuk penerima tembusan, bcc() untuk penerima tersembunyi, dan replyTo() agar balasan diarahkan ke alamat support.

Output yang Dihasilkan:

text
[2026-10-13 19:25:31] local.DEBUG: From: Laravel <[email protected]>
To: Budi <[email protected]>
Cc: [email protected]
Reply-To: [email protected]
Subject: Terima kasih atas pesanan Anda
MIME-Version: 1.0
Date: Tue, 13 Oct 2026 19:25:31 +0000
Message-ID: <[email protected]>
Content-Type: text/html; charset=utf-8
Content-Transfer-Encoding: quoted-printable

Halo Budi,

Terima kasih sudah berbelanja di toko kita.

Salam,
Toko Latihan

Dua hal menarik dari log ini. Pertama, To: Budi <[email protected]> — nama tampilan dari argument kedua to() ikut terformat. Kedua, Content-Type: text/html padahal template kita hanya teks: Mail::send() selalu merender view sebagai bagian HTML dari pesan multipart. Baris Bcc: sengaja tidak muncul di header — kalau muncul, penerima utama bisa membaca daftar tersembunyi. Penerima bcc tetap menerima email, hanya dihapus dari header sebelum pesan dikirim.

PendingMail: Rantai to()->send() #

Gaya Mail::to(...)->send(...) adalah alternatif yang lebih mudah dibaca ketika penerima sudah jelas. Method Mail::to() mengembalikan objek Illuminate\Mail\PendingMail yang menyimpan daftar penerima, lalu send() mengeksekusi pengiriman:

php
use App\Mail\OrderShipped;
use Illuminate\Support\Facades\Mail;

Mail::to('[email protected]')->send(new OrderShipped('123', 'Budi'));

Pola ini bersinar saat dipasangkan dengan Mailable — class OrderShipped di atas adalah mailable yang akan kita bangun di chapter berikutnya. Rantainya juga bisa diperpanjang sebelum send():

php
Mail::to('[email protected]')
    ->cc('[email protected]')
    ->bcc('[email protected]')
    ->send(new OrderShipped('123', 'Budi'));

Tabel Ringkas API Pengiriman #

MethodPeran
Mail::raw($isi, $closure)Kirim teks mentah tanpa view
Mail::send($view, $data, $closure)Kirim dengan view Blade + data
Mail::to($penerima)Mulai rantai penerima (user/string/array)
$message->to/cc/bcc/replyTo()Header amplop di dalam closure
$message->subject($judul)Judul email
Mail::mailer('log')Kirim lewat mailer non-default

Method to() juga menerima model User secara langsung — Laravel membaca properti email dari notifiable — sehingga Mail::to($user) cukup untuk seluruh aplikasi berbasis user.

Dengan dua gaya pengiriman ini kita sudah bisa mengirim email apa pun. Namana closure yang panjang di controller cepat menumpuk — dan di situlah Mailable masuk: class khusus yang memindahkan seluruh definisi email (amplop, konten, lampiran) keluar dari logic pengiriman.