Posts | About | Tools

How To Queue Laravel User Verification Email

May 16, 2020 by Areg Sarkissian

In this article I will show you how to change the out of the box Laravel configuration to queue new user verification emails.

For queuing password reset emails see:

How To Queue Laravel Password Reset Email

Enabling Email verification

In this section will quickly repeat the steps required to setup the new user verification email notification.

I will first describe how to make the user registration feature flow send a non queued user verification email.

In order to do that we need to first make the App\User class implement the Illuminate\Contracts\Auth\MustVerifyEmail contract.

class User extends Authenticatable implements MustVerifyEmail

Note that the use Illuminate\Contracts\Auth\MustVerifyEmail; statement is already included in the User.php file. So all we had to do is add the implements MustVerifyEmail to the class declaration.

The last thing we need to do is to enable the sending of the verification email by the framework.

To do that we need to make the Auth::routes method take a ['verify' => true] input argument.

Auth::routes(['verify' => true]);

By default Laravel triggers a notification when a user completes the registration step to send a verification email when the Auth::routes method has this feature enabled via the ['verify' => true] parameter.

Queuing the verification email

The email verification email is not queued by default and is sent as part of the registration request flow when enabled.

The framework triggers a notification to send the email verification email after the user is added to the database.

The notification sends the email by calling the sendEmailVerificationNotification() method on the App\User class. The sendEmailVerificationNotification method is included in the App\User class through the Illuminate\Foundation\Auth\User class (aliased as Authenticatable) that is extended by App\User:

namespace App;

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;

//This App\User class extends the Illuminate\Foundation\Auth\User class that is aliased to Authenticatable above
class User extends Authenticatable implements MustVerifyEmail
{
 use Notifiable;
}

The Illuminate\Foundation\Auth\User class implements the Illuminate\Auth\MustVerifyEmail trait (Not to be confused with the Illuminate\Contracts\Auth\MustVerifyEmail contract that App\User needs to implement) that in turn contains the default implementation of the sendEmailVerificationNotification method::

namespace Illuminate\Foundation\Auth;
class User extends Model implements
    AuthenticatableContract,
    AuthorizableContract,
    CanResetPasswordContract
{
    use Authenticatable, Authorizable, CanResetPassword, MustVerifyEmail;
}

Here is the default sendEmailVerificationNotification implementation in the Illuminate\Auth\MustVerifyEmail trait:

namespace Illuminate\Auth;

use Illuminate\Auth\Notifications\VerifyEmail;

trait MustVerifyEmail
{
    public function sendEmailVerificationNotification()
    {
        $this->notify(new VerifyEmail);
    }
}

Because sendEmailVerificationNotification method is included as a trait in the extended Illuminate\Foundation\Auth\User class, we can override its default implementation by simply implementing a sendEmailVerificationNotification method in the App\User class with our overridden implementation that will queue the delivery of user verification notification email.

We can take one of two approaches for the implementation within the overridden sendEmailVerificationNotification method:

Approach 1 - We can queue the notification

Approach 2 - We can dispatch a queued job that sends the notification

These approaches are shown in the next two sections.

Approach 1 - Queuing the notification approach

With this approach we will extend the Illuminate\Auth\Notifications\VerifyEmail notification, that the Illuminate\Auth\MustVerifyEmail trait sends, into a queue-able notification and queue this extended notification in the overridden sendEmailVerificationNotification method that we will add to the App\User class.

So first we create, in the \App\Notifications\Auth directory, a new QueuedVerifyEmail notification that extends the Illuminate\Auth\Notifications\VerifyEmail notification:

artisan make:notification Auth/QueuedVerifyEmail

This command creates the class \App\Notifications\Auth\QueuedVerifyEmail

Next we make this class extend the Illuminate\Auth\Notifications\VerifyEmail class and implement the Illuminate\Contracts\Queue\ShouldQueue contract

Finally we add the Illuminate\Bus\Queueable trait to the body of the class.

That is all we need to do to make a new QueuedVerifyEmail notification that is queue-able.

Below is the our final QueuedVerifyEmail notification class:

namespace App\Notifications\Auth;

use Illuminate\Auth\Notifications\VerifyEmail;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Bus\Queueable;

class QueuedVerifyEmail extends VerifyEmail implements ShouldQueue
{
    use Queueable;
}

Now we need to add the sendEmailVerificationNotification() method to the App\User class which will override the default method that it gets from the MustVerifyEmail trait of its parent class. Then we can notify the user using the QueuedVerifyEmail notification to substitute our new queued notification instead of the original notification.

class User extends Authenticatable implements MustVerifyEmail
{
    use Notifiable;

    //Overrideen sendEmailVerificationNotification implementation
    public function sendEmailVerificationNotification()
    {
        $this->notify(new \App\Notifications\Auth\QueuedVerifyEmail);
    }
}

Optionally we can add a constructor to the QueuedVerifyEmail class to queue the notifications to a different queue and/or different connection from the default connection and queue.

class QueuedVerifyEmail extends VerifyEmail implements ShouldQueue
{
    use Queueable;

    public function __construct()
    {
        //uncomment to override the queue
        //$this->queue = 'verify';

        //uncomment to override the connection
        //$this->connection = 'verify';
    }
}

Approach 2 - Queueing a job that sends the notification approach

In this approach we create a queued job that we dispatch in the overridden sendEmailVerificationNotification method of the App\User class.

When the job is processed, it will send the original Illuminate\Auth\Notifications\VerifyEmail notification that was being sent directly from the overridden sendEmailVerificationNotification method.

So we first need to create a job that will be queued.

artisan make:job QueuedVerifyEmailJob

Next in the handle() method of the job we need to copy a slightly modified implementation from the original sendEmailVerificationNotification() method as shown below:

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 Illuminate\Auth\Notifications\VerifyEmail;
use App\User;

class QueuedVerifyEmailJob implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    protected $user;

    public function __construct(User $user)
    {
        //the user property passed to the constructor through the job dispatch method
        $this->user = $user;
    }

    public function handle()
    {
        //This queued job sends
        //Illuminate\Auth\Notifications\VerifyEmail verification
        //to the user by triggering the notification
        $this->user->notify(new VerifyEmail);
    }
}

Finally we need to override the default sendEmailVerificationNotification() method implementation by adding a sendEmailVerificationNotification() method directly to the App\User class where we will dispatch the QueuedVerifyEmailJob to the queue.

class User
{
    public function sendEmailVerificationNotification()
    {
        //dispactches the job to the queue passing it this User object
         QueuedVerifyEmailJob::dispatch($this);
    }
}

Looking back at the QueuedVerifyEmailJob class we can see that the implementation we added to its handle() method is slightly different than the implementation of the original sendEmailVerificationNotification method.

The handle() method of the job class calls $this->user->notify where the original sendEmailVerificationNotification method in the MustVerifyEmail trait calls $this->notify.

This is because in the original implementation, the $this pointer refers to the App\User class that includes the trait. But in the Job class the $this pointer refers to the job class so we need to reference the user property of the job class then call the notify method on the user.

Protecting routes that require verified users

In order to protect routes from allowing access to users that have not verified their email we can use the verified middleware.

The example below shows that the middleware is added to the constructor of a controller. We could also apply the middleware to the routes directly instead of to the controller.

public function __construct()
{
    $this->middleware('auth','verified');
}

It should be noted that the verified middleware checks and authenticated user if they have verified their email by checking the database record for the App\User. So if users that are not authenticated automatically are not verified.