Skip to main content

Documentation Index

Fetch the complete documentation index at: https://kawax.biz/llms.txt

Use this file to discover all available pages before exploring further.

Introduction

Laravel’s mail system is powered by Symfony Mailer and supports SMTP, Mailgun, Postmark, Resend, Amazon SES, and sendmail out of the box. Each type of email you send is represented as a mailable class. Mailables encapsulate all the configuration—who it’s from, the subject, the view, and attachments—in one place.

Configuration

Mail configuration lives in config/mail.php. Set the default driver and credentials via .env:
MAIL_MAILER=smtp
MAIL_HOST=smtp.mailgun.org
MAIL_PORT=587
MAIL_USERNAME=your-username
MAIL_PASSWORD=your-password
MAIL_FROM_ADDRESS[email protected]
MAIL_FROM_NAME="My App"
DriverInstall
Mailguncomposer require symfony/mailgun-mailer symfony/http-client
Postmarkcomposer require symfony/postmark-mailer symfony/http-client
Resendcomposer require resend/resend-php
Amazon SEScomposer require aws/aws-sdk-php
After installing the package, set MAIL_MAILER in .env to the driver name (mailgun, postmark, resend, or ses) and add the corresponding credentials to config/services.php.

Generating mailables

Create a mailable class with Artisan:
php artisan make:mail OrderShipped
This generates app/Mail/OrderShipped.php.

Writing mailables

A mailable class defines three methods:
  • envelope() — from address and subject
  • content() — the Blade view to render
  • attachments() — files to attach
<?php

namespace App\Mail;

use App\Models\Order;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Address;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
use Illuminate\Queue\SerializesModels;

class OrderShipped extends Mailable
{
    use Queueable, SerializesModels;

    /**
     * Create a new message instance.
     */
    public function __construct(
        public Order $order,
    ) {}

    /**
     * Get the message envelope.
     */
    public function envelope(): Envelope
    {
        return new Envelope(
            subject: 'Your Order Has Shipped',
        );
    }

    /**
     * Get the message content definition.
     */
    public function content(): Content
    {
        return new Content(
            view: 'emails.orders.shipped',
        );
    }

    /**
     * Get the attachments for the message.
     *
     * @return array<int, \Illuminate\Mail\Mailables\Attachment>
     */
    public function attachments(): array
    {
        return [];
    }
}
Public properties of the mailable are automatically available in the Blade view:
{{-- resources/views/emails/orders/shipped.blade.php --}}
<p>Your order #{{ $order->id }} has shipped!</p>
<p>Estimated delivery: {{ $order->estimated_delivery->format('M j, Y') }}</p>

Adding attachments

Attach files using the Attachment class:
use Illuminate\Mail\Mailables\Attachment;

public function attachments(): array
{
    return [
        Attachment::fromPath(storage_path('invoices/'.$this->order->id.'.pdf'))
            ->as('invoice.pdf')
            ->withMime('application/pdf'),
    ];
}

Markdown mailables

Markdown mailables use Laravel’s pre-built email components to produce responsive, well-designed emails without writing custom HTML. Generate a Markdown mailable:
php artisan make:mail OrderShipped --markdown=emails.orders.shipped
This creates the mailable class and a Markdown Blade template at resources/views/emails/orders/shipped.blade.php:
<x-mail::message>
# Order Shipped

Your order #{{ $order->id }} has shipped.

<x-mail::button :url="route('orders.show', $order)">
View Order
</x-mail::button>

Thanks,<br>
{{ config('app.name') }}
</x-mail::message>
The content method uses markdown instead of view:
public function content(): Content
{
    return new Content(
        markdown: 'emails.orders.shipped',
    );
}
Markdown mailables are the easiest way to create good-looking transactional emails. Laravel handles the responsive HTML and plain-text fallback automatically.

Sending mail

Use the Mail facade to send a mailable:
use App\Mail\OrderShipped;
use Illuminate\Support\Facades\Mail;

Mail::to($request->user())->send(new OrderShipped($order));
Send to multiple recipients:
Mail::to($order->user)
    ->cc($manager)
    ->bcc('[email protected]')
    ->send(new OrderShipped($order));

Queueing mail

Email sending can be slow. Queue the mailable to return a response immediately:
Mail::to($request->user())->queue(new OrderShipped($order));
To make a mailable always queue when sent, implement ShouldQueue on the class:
use Illuminate\Contracts\Queue\ShouldQueue;

class OrderShipped extends Mailable implements ShouldQueue
{
    use Queueable, SerializesModels;

    // ...
}
Now Mail::to(...)->send(new OrderShipped($order)) queues automatically.

Sending after the response

Use Mail::to(...)->sendNow() or Mail::later() to control timing. To send right after Laravel returns the HTTP response:
Mail::to($request->user())
    ->queue((new OrderShipped($order))->delay(now()->addMinutes(5)));

Previewing mailables in the browser

Return a mailable from a route to inspect it during development:
use App\Mail\OrderShipped;
use App\Models\Order;

Route::get('/mailable', function () {
    $order = Order::first();
    return new OrderShipped($order);
});

Testing mailables

Assert a mailable was sent without actually sending email:
use App\Mail\OrderShipped;
use Illuminate\Support\Facades\Mail;

test('order confirmation is emailed', function () {
    Mail::fake();

    $order = Order::factory()->create();

    $this->post("/orders/{$order->id}/ship");

    Mail::assertSent(OrderShipped::class, function ($mail) use ($order) {
        return $mail->order->id === $order->id;
    });
});

Local development

During development, set the log mailer to write all outgoing emails to your log file instead of sending them:
MAIL_MAILER=log
Or use Mailpit to catch emails locally:
MAIL_MAILER=smtp
MAIL_HOST=127.0.0.1
MAIL_PORT=1025

A complete example

1

Generate the mailable

php artisan make:mail WelcomeMail --markdown=emails.welcome
2

Define the mailable class

<?php

namespace App\Mail;

use App\Models\User;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
use Illuminate\Queue\SerializesModels;

class WelcomeMail extends Mailable implements ShouldQueue
{
    use Queueable, SerializesModels;

    public function __construct(
        public User $user,
    ) {}

    public function envelope(): Envelope
    {
        return new Envelope(
            subject: 'Welcome to '.config('app.name'),
        );
    }

    public function content(): Content
    {
        return new Content(
            markdown: 'emails.welcome',
        );
    }

    public function attachments(): array
    {
        return [];
    }
}
3

Write the Blade template

{{-- resources/views/emails/welcome.blade.php --}}
<x-mail::message>
# Welcome, {{ $user->name }}!

Thanks for signing up. Click below to get started.

<x-mail::button :url="url('/')">
Go to Dashboard
</x-mail::button>

Thanks,<br>
{{ config('app.name') }}
</x-mail::message>
4

Send after user registration

use App\Mail\WelcomeMail;
use Illuminate\Support\Facades\Mail;

public function store(Request $request): RedirectResponse
{
    $user = User::create($request->validated());

    Mail::to($user)->send(new WelcomeMail($user));

    return redirect('/dashboard');
}

Notifications

Send multi-channel notifications—email, SMS, Slack, and database—with a single notification class.
Last modified on April 19, 2026