Easy and Fast Emails with Laravel 5.3 Mailables

An easier and more readable way to send Laravel emails.

Laravel 5.3 has just been released and there are a ton of great new features. One of the major improvements is in how you send mail in your applications.

Let's take a look at sending emails. Before Laravel 5.3, sending emails in Laravel looked a lot like this.

Mail::send('emails.send', ['title' => $title, 'message' => $message], function ($message)
 {
    $message->from('no-reply@scotch.io', 'Scotch.IO');
    $message->to('batman@batcave.io');
});

This method worked for a while, but after sending a couple of emails, the code base got messy. Since I didn't really like this method, I found myself using event listeners to build emails.

Installing Laravel 5.3

At the time of this article, installing Laravel 5.3 with Laravel installer is as simple as.

laravel new project

Introducing Mailables

Mailables in Laravel abstracts building emails with a mailable class. Basically, mailables are responsible for collating data and passing them to views. Meanwhile, the API for sending emails got really simple.

To send emails in Laravel, all we have to do now is.

Mail::to('batman@batcave.io')->send(new KryptoniteFound);

Don't get me wrong, the previous API will work just fine (and it will still work in your applications) — it's just that the Mail API got a whole lot simpler.

Creating a Mailable

With artisan our super handy Laravel cli-tool, we can simply create a mailable like this.

php artisan make:mail <NameOfMailable>

Since our mailable's name is KryptoniteFound, we can create our mailable using this command.

php artisan make:mail KryptoniteFound

Creating a laravel 5.3 mailable

After we've created our mailable, in app/mail, we can see our newly created mailable class.

namespace App\Mail;

use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;

class KryptoniteFound extends Mailable
{
    use Queueable, SerializesModels;

    public function __construct()
    {
        //
    }

    public function build()
    {
        return $this->view('view.name');
    }
}

The created class should look like the snippet above (comments stripped).

As we can see, the build method builds the message. For our case, we can replace the view.name with the path to our email view email.kryptonite-found.

In resources/views create a new blade template in an email folder called kryptonite-found.blade.php.

Passing Data to Email Views

Any public property on your mailable class is automatically made available to your view file. So passing data to your views is as simple as making the data public on the mailable class.

Say for example I wanted to pass the weight of kryptonites found, all I need to do is expose the total on the mailable like this.

public $total = 30;

While in our view template, we access the data like a normal variable.

<h1>Woot Woot!!</h1>

<p>Alfred just found <strong>{{ $total }}lbs</strong> of kryptonite</p>

We can also explicitly set data using the with method.

public function build()
{
    return $this->view('emails.kryptonite-found')
                ->with($key, $value);
}

Configuring our Mailer

To send emails, we will use mailtrap. For other service configuration like Amazon SES, Chris wrote an article on the topic.

Next, we move to our .env file and configure our mail credentials.

MAIL_DRIVER="smtp"
MAIL_HOST="mailtrap.io"
MAIL_PORT=2525
MAIL_USERNAME=31230cade12007610
MAIL_PASSWORD=24280ed5ee934c
MAIL_ENCRYPTION=null

You replace MAIL_USERNAME and MAIL_PASSWORD with your mailtrap details. Using the credentials above won't work.

Still, on the issue of configuring mail, we also need to configure the mailers from details. In config/mail.php, look for an array from key and configure the address and name. If you are satisfied with the defaults, you can just leave it. But, under no condition can it be null.

Sending Extra Parameters

Adding bcc, cc and the rest can be called on $this in the build method.

public function build()
{
    $address = 'ignore@batcave.io';
    $name = 'Ignore Me';
    $subject = 'Krytonite Found';

    return $this->view('emails.kryptonite-found')
                ->from($address, $name)
                ->cc($address, $name)
                ->bcc($address, $name)
                ->replyTo($address, $name)
                ->subject($subject);
}

Sending Emails

Previously, our routes were located in app/Http/routes.php, but with this release routes are now in app/routes. Now we can use routes based on the interface (web, api or console). For this tutorial, we only need the web.php routes file.

use App\Mail\KryptoniteFound;

Route::get('/', function () {
    // send an email to "batman@batcave.io"
    Mail::to('batman@batcave.io')->send(new KryptoniteFound);

    return view('welcome');
});

Now, we can start our Laravel server by running the following artisan command.

php artisan serve

We can trigger an email by visiting http://localhost:8080.

Queuing Emails

To queue emails, instead of calling send on the Mail::to, just call the queue method and pass it the mailable.

Mail::to('batman@batcave.io')->queue(new KryptoniteFound);

Delay Message Queueing

To delay a queued email, we use the later method. This method takes in two parameters. The first is a DateTime object that represents the time to wait. The second parameter is mailable.

$when = Carbon\Carbon::now()->addMinutes(10);

Mail::to('batman@batcave.io')->later($when, new KryptoniteFound);

Conclusion

Laravel 5.3 offers a lot of promising features like notifications, oAuth, search etc. Watch out for them.

Samuel Oloruntoba

Self-proclaimed full-stack web developer and a quasi-academic. I work mostly on the backend (PHP and Node) with a recent enthusiasm for frontend development (React, SVG, HTML5 Canvas).