Posts | About | Tools

Laravel App Sending Email Using Background Job

May 13, 2020 by Areg Sarkissian

In this article I will show you how we can create a Laravel background job that sends an email using the Mailable class.

I will also show how to queue that job using a Redis backed queue and to process the queued job using a Laravel queue worker.

Before we can queue jobs we need a mail server to test sending emails to. I have covered configuring a local email server running in a docker container here:

Laravel App With Mail Server In Docker.

Also we will need to configure our Laravel project to use redis in a docker container. I have covered that here:

Laravel App With Redis In Docker

This article assumes we are using the configurations in the above referenced links to send and view the emails.

Creating the html text and plain text email blade templates

We will create two email templates to deliver email in both Html and plain text formats.

First we will create the html template by creating the following blade template file:

touch resources/views/mails/welcomeemail.blade.php

This will create the resources/views/mails/welcomeemail.blade.php template file.

Next we will put the following html markup in resources/views/mails/welcomeemail.blade.php file.

<!DOCTYPE html>
<html>
<head>
<title>Welcome</title>
</head>
<body>
Welcome to our app
</body>
</html>

Finally we will create the plane text template by creating the following blade template file with raw text inside:

touch resources/views/mails/welcomeemail-text.blade.php
echo 'Welcome to our app' > resources/views/mails/welcomeemail-text.blade.php

This will create the resources/views/mails/welcomeemail-text.blade.php plain text template file.

Creating the Mailable

Now that we have the email templates we will create the Mailable class file for our email:

php artisan make:mail WelcomeEmail

This will create the App/Mail/welcomeemail.php plain text template file.

The artisan command will create the App/Mail/WelcomeEmail.php file.

We will need to replace the initial content of the build() method after we created the file, with the content of the build() method show below:

<?php
  
namespace App\Mail;
  
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;
  
class WelcomeEmail extends Mailable
{
    use Queueable, SerializesModels;
  
    public function __construct()
    {
    }
  
    public function build()
    {
        //The mails.welcomeemail is a html blade template
        //the mails.welcomeemail-text is a text blade template as a fallback
        //either one can be removed if we want to only send html or text email
        return $this->from('admin@myapp.com', 'Admin')
                    ->subject('Welcome')
                    ->view('mails.welcomeemail')
                    ->text('mails.welcomeemail-text');
    }
}

Creating the Email Job

Now that we have created the email templates and the Mailable class that builds the email, we will create the job that will send the Mailable.

php artisan make:job WelcomeEmailJob

This will create the App/Jobs/WelcomeEmailJob.php job class.

Next we need to replace the implementation in the initial file with the implementation below:

<?php
  
namespace App\Jobs;

use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use App\Mail\WelcomeEmail;
use Mail;

class WelcomeEmailJob implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
  
    protected $to;
  
    public function __construct($email)
    {
        $this->to = $email;
    }

    /**
     * Execute the job.
     */
    public function handle()
    {
        Mail::to($this->to)->send(new WelcomeEmail);
    }
}

Dispatching the Email Job

Now that we have our job created, we will need to dispatch the job to the Redis queue from within a controller action.

In order to do that we must first add the following route to the routes/web.php file:

Route::get('welcome', 'WelcomeEmailController@send');

Next we can create a WelcomeEmailController controller class:

php artisan make:controller WelcomeEmail

This command will create the WelcomeEmailController.php file.

Then we can add the following implementation in the controller file:

namespace App\Http\Controllers;

use Illuminate\Http\Request;

use App\Http\Controllers\Controller;

use App\Jobs\WelcomeEmailJob;

class WelcomeEmailController extends Controller
{
    public function send(Request $request)
    {
        WelcomeEmailJob::dispatch('recipient@example.com');

        //Alternative way of dispaching Job
        //dispatch(new WelcomeEmailJob('recipient@example.com'));

        //override the default connection
        //override the default queue of the connection
        //you can override both or one or the other
        //WelcomeEmailJob::dispatch('recipient@example.com')->onConnection('sqs')->onQueue('processing');
    }
}

When we navigate to the url http://localhost/welcome, the WelcomeEmailController:: send action will send the WelcomeEmailJob to our redis queue running in the docker container.

Processing the queued emails

At this point we have dispatched the job to our redis queue but have not sent the email since the job has not been processed yet.

To remedy that, we can run the following artisan command to launch and run a single worker process to process jobs in the queue:

php artisan queue:work --tries=3 --timeout=30

The worker process will pull the WelcomeEmailJob job from the queue and process it by calling its handle() method. The handle method implementation will then send the WelcomeEmail email to the mailhog mail server running in the docker container.

If we navigate to http://localhost:8100 we can see the email that was sent in the mailhog server dashboard.

Further customizations

For further customizations of the Laravel email features see https://blog.mailtrap.io/laravel-mail-queue/.