Learn how to send emails in Laravel 12 using Mailables, SMTP, Markdown, and queues. This guide covers configuration, email templates, attachments, and testing for robust Laravel email workflows.

Sending emails is a common requirement in modern web applications—for user registration, password resets, notifications, and more. Laravel 12 provides a clean, expressive API to compose, queue, and deliver emails using a variety of drivers. In this tutorial, we’ll cover:
- Configuration of mail settings
- Creating a Mailable class
- Building email views (Blade and Markdown)
- Sending emails (synchronously and queued)
- Adding attachments
- Testing email functionality
Prerequisites
- A Laravel 12 application set up
- PHP 8.1+
- Composer installed
- Access to an SMTP service (e.g., Mailtrap, SendGrid, Mailgun)
1. Configure Mail Settings
Open your project’s .env
file and add your SMTP credentials:
MAIL_MAILER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=your_username
MAIL_PASSWORD=your_password
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS=no-reply@yourapp.com
MAIL_FROM_NAME="YourAppName"
Then verify config/mail.php
picks up these values:
return [
'default' => env('MAIL_MAILER', 'smtp'),
'mailers' => [
'smtp' => [
'transport' => 'smtp',
'host' => env('MAIL_HOST'),
'port' => env('MAIL_PORT'),
'encryption' => env('MAIL_ENCRYPTION'),
'username' => env('MAIL_USERNAME'),
'password' => env('MAIL_PASSWORD'),
],
// other mailers...
],
'from' => [
'address' => env('MAIL_FROM_ADDRESS'),
'name' => env('MAIL_FROM_NAME'),
],
];
2. Create a Mailable Class
Laravel’s Mailables encapsulate email logic and content. Generate one with Artisan:
php artisan make:mail PasswordResetMail
This creates app/Mail/PasswordResetMail.php
. Open it and update the build()
method:
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class PasswordResetMail extends Mailable
{
use Queueable, SerializesModels;
public $token;
public function __construct(string $token)
{
$this->token = $token;
}
public function build()
{
return $this
->subject('Reset Your Password')
->markdown('emails.password_reset')
->with([
'resetUrl' => url("/password/reset/{$this->token}")
]);
}
}
Here, we’re using Laravel 12’s built-in Markdown mail feature for nicer styling.
3. Create the Email Template
Markdown Template
Create resources/views/emails/password_reset.blade.php
:
@component('mail::message')
# Reset Your Password
Click the button below to reset your password:
@component('mail::button', ['url' => $resetUrl])
Reset Password
@endcomponent
If you did not request a password reset, no further action is required.
Thanks,<br>
{{ config('app.name') }}
@endcomponent
Laravel will automatically generate the HTML and plain-text views from this Markdown.
4. Send the Email
You can send mails synchronously or queue them for better performance.
a) Synchronous Sending
In a controller or route:
use App\Mail\PasswordResetMail;
use Illuminate\Support\Facades\Mail;
Route::get('/test-reset', function () {
$token = Str::random(64);
Mail::to('user@example.com')->send(new PasswordResetMail($token));
return 'Password reset email sent!';
});
b) Queueing Emails
First, configure your queue driver in .env
(e.g., Redis, database):
QUEUE_CONNECTION=database
Run migrations for the jobs table:
php artisan queue:table
php artisan migrate
Mark the Mailable as queueable (it already uses Queueable
), then dispatch:
Mail::to('user@example.com')
->queue(new PasswordResetMail($token));
Start a worker:
php artisan queue:work
5. Attach Files (Optional)
To attach files, use attach()
in your build()
public function build()
{
return $this->subject('Your Report')
->view('emails.report')
->attach(storage_path('reports/monthly.pdf'));
}
6. Testing Your Emails
Laravel provides testing helpers to assert mail was sent:
use Illuminate\Support\Facades\Mail;
use App\Mail\PasswordResetMail;
use Tests\TestCase;
class MailTest extends TestCase
{
public function test_password_reset_mail_is_sent()
{
Mail::fake();
$token = Str::random(64);
Mail::to('test@example.com')->send(new PasswordResetMail($token));
Mail::assertSent(PasswordResetMail::class, function ($mail) use ($token) {
return $mail->token === $token &&
$mail->hasTo('test@example.com');
});
}
}
Conclusion
By following this guide, you now know how to configure Laravel 12’s mail settings, create Mailables, craft Markdown templates, send (and queue) emails, add attachments, and write tests. Laravel’s elegant mail API makes integrating email into your application straightforward and maintainable.
Happy Coding! 😊