How To Queue Laravel Password Reset Email
May 14, 2020 by Areg Sarkissian
In this article I will show you how to change the out of the box Laravel configuration to queue password reset emails.
For queuing User Verification Emails see:
How To Queue Laravel User Verification Email
Queuing the Password Reset email
The Laravel authentication framework sends a non queued password reset notification as part of the password reset flow.
The password reset notification sends the email by calling the sendPasswordResetNotification()
method on the App\User
class.
The sendPasswordResetNotification
method is inherited by the App\User
class from the Illuminate\Foundation\Auth\User
class (aliased as Authenticatable
) which the App\User
class extends:
namespace App;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
//we are extending the Illuminate\Foundation\Auth\User class that is aliased to Authenticatable above
class User extends Authenticatable
{
use Notifiable;
}
The Illuminate\Foundation\Auth\User
class implements the Illuminate\Auth\CanResetPassword
trait that in turn contains the default implementation of the sendPasswordResetNotification
method:
namespace Illuminate\Foundation\Auth;
class User extends Model implements
AuthenticatableContract,
AuthorizableContract,
CanResetPasswordContract
{
use Authenticatable, Authorizable, CanResetPassword, MustVerifyEmail;
}
Here is the default sendPasswordResetNotification
implementation in the CanResetPassword
trait:
namespace Illuminate\Auth\Passwords;
use Illuminate\Auth\Notifications\ResetPassword as ResetPasswordNotification;
trait CanResetPassword
{
public function sendPasswordResetNotification($token)
{
$this->notify(new ResetPasswordNotification($token));
}
}
Because sendPasswordResetNotification
method is included as a trait in the extended Illuminate\Foundation\Auth\User
class, we can override its default implementation by simply implementing a sendPasswordResetNotification
method in the App\User
class with our overridden implementation that will queue the delivery of reset notification email.
We can take one of two approaches for the implementation within the overridden sendPasswordResetNotification
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\ResetPassword
notification that the Illuminate\Auth\CanResetPassword
trait sends, into a queue-able notification. Then we will queue this extended notification from the overridden sendPasswordResetNotification
method implementation that we will add to the App\User
class.
So first let’s create, in the \App\Notifications\Auth
directory, a new QueuedResetPassword
notification that extends the Illuminate\Auth\Notifications\ResetPassword
notification:
artisan make:notification Auth/QueuedResetPassword
This command creates the class \App\Notifications\Auth\QueuedResetPassword
.
Next we make this class extend the Illuminate\Auth\Notifications\ResetPassword
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 QueuedResetPassword
notification that is queue-able.
Below is the our final QueuedResetPassword
notification class:
namespace App\Notifications\Auth;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Bus\Queueable;
use Illuminate\Auth\Notifications\ResetPassword;
class QueuedResetPassword extends ResetPassword implements ShouldQueue
{
use Queueable;
}
Now we need to add the sendPasswordResetNotification()
method to the App\User
class which will override the default method that it gets from the CanResetPassword
trait of its parent class. Then we can notify the user using the QueuedResetPassword
notification to substitute our new queued notification instead of the original notification.
class User extends Authenticatable
{
use Notifiable;
//Overrideen sendPasswordResetNotification implementation
public function sendPasswordResetNotification($token)
{
$this->notify(new \App\Notifications\Auth\QueuedResetPassword($token));
}
}
Optionally we can add a constructor to the QueuedResetPassword
class to queue the notifications to a different queue and/or different connection from the default connection and queue.
class QueuedResetPassword extends ResetPassword implements ShouldQueue
{
use Queueable;
public function __construct()
{
//uncomment to override the queue
//$this->queue = 'reset';
//uncomment to override the connection
//$this->connection = 'reset';
}
}
Approach 2 - Queueing a job that sends the notification approach
In this approach we create a queued job that we dispatch in the overridden sendPasswordResetNotification
method of the App\User
class.
When the job is processed, it will send the original Illuminate\Auth\Notifications\ResetPassword
notification that was being sent directly from the overridden sendPasswordResetNotification
method.
So first we need to create a job that will be queued.
artisan make:job QueuedPasswordResetJob
Next in the handle()
method of the job we need to copy a slightly modified implementation from the original sendPasswordResetNotification()
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\ResetPassword;
use App\User;
class QueuedPasswordResetJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $user;
protected $token;
public function __construct(User $user, $token)
{
//the user property passed to the constructor through the job dispatch method
$this->user = $user;
$this->token = $token;
}
public function handle()
{
//This queued job sends
//Illuminate\Auth\Notifications\ResetPassword notification
//to the user by triggering the notification
$this->user->notify(new ResetPassword($this->token));
}
}
Finally we need to override the default sendPasswordResetNotification()
method implementation by adding a sendPasswordResetNotification()
method directly to the App\User
class where we will dispatch the QueuedPasswordResetJob
to the queue.
class User extends Authenticatable
{
public function sendPasswordResetNotification($token)
{
//dispactches the job to the queue passing it this User object
QueuedPasswordResetJob::dispatch($this,$token);
}
}
Looking back at the QueuedPasswordResetJob
class we can see that the implementation we added to its handle()
method is slightly different than the implementation of the original sendPasswordResetNotification
method.
The handle()
method of the job class calls $this->user->notify
where the original sendPasswordResetNotification
method in the CanResetPassword
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.
Customizing the redirect location after reseting password
By default the user will be automatically logged in and redirected to the /home
URL after reseting their password, to override this we can define a redirectTo
property on the Auth\ResetPasswordController
like so:
protected $redirectTo = '/mynewhome';
This will then override and redirect them to the /mynewhome
URL instead.