Laravel Mailable Tutorial

Valerio Barbera

Sending emails in Laravel requires the collaboration between three components: Laravel mailer, Laravel mailable classes, and the Mail facade. Each of the three deals with a different aspect of the lifecycle of sending an email. 

Mailers are the drivers to connect email sending services (like AWS SES, Sendgrid, Mailgun, etc.) that the application can use to forward emails to the recipients. 

Laravel Mailable are special classes that represent a template of email to send. It contains all the typical information of an email message like the content, the “to” field, attachments, etc.

Finally, the Mail facade is the access point to request the actual sending of a mailable through a mailer driver.

I had the opportunity to explore this system in detail and now at peak Inspector sends more than 6000 emails per hour.

I hope my experience could be helpful for you to better understand this component of the framework since Laravel Mailable is one of the key components of any modern application.

Laravel Mailers Configurations

The configuration of mailer drivers in Laravel is in the config/mail.php file. It is possible to define several mailers, each characterized by a name and a transport driver.

'mailgun' => [
    'transport' => 'mailgun',
    // 'client' => [
    //     'timeout' => 5,
    // ],
],

In this way, Laravel allows you to not only configure the available mail servers, but to use different servers or emailing services to send different types of email messages. This possibility is very important for applications that have to send both transactional emails, and bulk emails. Transactional emails are those that are sent in response to a specific user action and which need to be delivered as soon as possible, such as those with codes to change passwords or confirmation of an order. Bulk emails instead are related to newsletters and other marketing messages, which may travel on slower channels.

You can configure the default mailer and failover mailers, in case any of the others fires exceptions.

'mailers' => [
    'failover' => [
        'transport' => 'failover',
        'mailers' => [
            'postmark',
            'mailgun',
            'sendmail',
        ],
    ],
 
    // ...
],

Laravel will try to use them in case the primary email service is down.

Create A Mailable Class

A mailable is a PHP class that represents an email sent by your application. You can create a new mailable class using the Artisan make command.

php artisan make:mail OrderConfirmation

The configuration of a mailable occurs through three main methods envelope, content and attachments, which respectively deal with defining the headers, the body of the message and any attachments.

use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailables\Address;
use Illuminate\Mail\Mailables\Attachment;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class OrderConfirmation extends Mailable
{
    use Queueable;
    use SerializesModels;
    public function __construct(public Order $order) {}
    /**
     * Configure the email message
     */
    public function envelope()
    {
        return new Envelope(
            from: new Address('[email protected]', 'E-commerce'),
            subject: 'Order Confirmation',
        );
    }
    /**
     * Generate the body
     */
    public function content()
    {
        return new Content(
            markdown: 'emails.orders.confirm',
        );
    }
    /**
     * Configure the email attachements
     */
    public function attachments()
    {
        $code = $this->order->code;
        return [
            Attachment::fromPath("/path/to/order-{$code}.pdf"),
        ];
    }
}

The rendering of the email content is, obviously, entrusted to the appropriate Blade template. Inside the Blade view it is possible to retrieve the data to be used for rendering the email using the public properties defined in the mailable class ($order in the example above).

Code: {{ $order->code }}
Address: {{ $order->address }}
...

Sending Laravel Mailable

The actual sending of an email occurs via the Mail facade and its “to” and “send” methods.

class OrderController extends Controller
{
    public function ship(Order $order)
    {
        // do stuff with the order
        // Send the confirmation email
        Mail::to($order->user)->send(new OrderConfirmation($order));
    }
}

The email recipient can be passed as an email address string or via a User object or collection of objects that have the name and email properties.

The actual email to be sent is represented by the mailable object, that receives the necessary properties to render the Blade template associated with the content.

The Mail facade offers various chainable methods that allow you to define in more detail the sending configuration, both as regards the recipients (with the cc and bcc methods) and the times and methods of sending (queue or later).

If you want learn how to create your own facades you can read the article below: 

Queue a Laravel Mailable

Since sending an email requires the use of external services (the Mailer drivers) it may be a slow operation with a negative impact on the user experience.

Laravel allows you to queue email messages for background sending. If you are interested in tutorial on how to use the Laravel queue system at scale you can read the article below:

To defer the sending of an email in the background you have two options: the ShouldQueue interface, or the queue method of the Mail facade.

As shown in a previous snippet, the mailable class is generated with some traits attached by default like Queueable.

It allows to programmatically use the queue methods on the Mail facade without touching your implementation:

Mail::to($user)->queue(new OrderConfirmation($order));

In alternative you can declare the implementation of the ShouldQueue interface in the Mailable class:

use Illuminate\Contracts\Queue\ShouldQueue;
class OrderConfirmation extends Mailable implements ShouldQueue
{
    ...
}

If you use this interface the sending of the email is always queued also if you call the standard send method on the Mail facade.

// If the mailable class implements ShouldQueue these methods has the same behaviour.
Mail::to($user)->send(new OrderConfirmation($order));
Mail::to($user)->queue(new OrderConfirmation($order));

Rendering the Laravel Mailable Template in the Browser

When you implement a view related to an email message it’s really helpful to have visual feedback of what the final result the Blade view will render.You can do it using the routes/mailable.php file in your Laravel projects.

/*
 * Render email in the browser.
 *
 * Visit https://homestead.test/mailable
 */
Route::get('/', function () {
    return new \App\Domains\Organization\Mails\IngestionLimitMail(
        \App\Domains\Organization\Models\Organization::firstOrFail()
    );
});

You can return a valid Mailable instance from the route and Laravel will render the view in the browser. It’s like developing a normal web page.

Finally remember to limit the availability of this route in the RouteServiceProvider:

class RouteServiceProvider extends ServiceProvider
{
    /**
     * Define your route model bindings, pattern filters, etc.
     *
     * @return void
     */
    public function boot()
    {
        if (app()->environment('local')) {
            $this->mapMailableRoutes();
        }
    }
	
    /**
     * Render mailables in the browser.
     *
     * @return void
     */
    protected function mapMailableRoutes()
    {
        Route::prefix('mailable')
            ->group(base_path('routes/mailable.php'));
    }
}

Autofix your Laravel application for free

Inspector is a Code Execution Monitoring tool specifically designed for software developers. You don’t need to install anything on the infrastructure, just install the Laravel package and you are ready to go.

If you are looking for effective automation, and the ability to automatically receive code change proposals to fix application errors try Inspector for free. Register your account.

Or learn more on the website: https://inspector.dev

Related Posts

Laravel Http Client Overview and Monitoring

Laravel HTTP client was introduced starting from version 10 of the framework, and then also made available in all previous versions. It stands out as a powerful tool for making HTTP requests and handling responses from external services. This article will delve into the technical foundations of the Laravel HTTP client, its motivations, and how

Laravel Form Request and Data Validation Tutorial

In this article I will talk about Laravel Form Request to send data from your application frontend to the backend. In web applications, data is usually sent via HTML forms: the data entered by the user into the browser is sent to the server and stored in the database eventually. Laravel makes it extremely simple

Upload File in Laravel

You can upload file in Laravel using its beautiful unified API to interact with many different types of storage systems, from local disk to remote object storage like S3. As many other Laravel components you can interact with the application filesystem through the Storage Facade: Illuminate/Support/Facades/Storage This class allows you to access storage drivers called