How to queue Laravel 5.7 "email verification" email sending
Asked Answered
S

4

8

Laravel 5.7 included "email verification" feature works well but not async email sending (during user register or resend link page) is not ideal.

Is there any way to send the email verification email through a queue without rewrite whole email verification in Laravel 5.7 ?

Shuffle answered 4/10, 2018 at 10:52 Comment(1)
I don't think this is possible at the moment. The new trait sends this email, which currently cannot be queued.Manno
S
53

There is no built in way, but you can do it easily by extending and overriding.

First, create a new notification that extends the built-in notification, and also implements the ShouldQueue contract (to enable queuing). The following class assumes you create a notification at app/Notifications/VerifyEmailQueued.php:

namespace App\Notifications;

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

class VerifyEmailQueued extends VerifyEmail implements ShouldQueue
{
    use Queueable;

    // Nothing else needs to go here unless you want to customize
    // the notification in any way.
}

Now you need to tell the framework to use your custom notification instead of the default one. You do this by overriding the sendEmailVerificationNotification() on your User model. This simply changes which notification gets sent out.

public function sendEmailVerificationNotification()
{
    $this->notify(new \App\Notifications\VerifyEmailQueued);
}
Salk answered 4/10, 2018 at 12:47 Comment(4)
Worked like a charn!Soothfast
this is so much simpler than the accepted answer, and it worksCouncil
This working, but when click on verification link (sent by email) it redirects to 403, Invalid Signature page. (Laravel 6)Papyrology
@IrfanGondal The notification is now going to be queued, so the URL in the notification will be built using your APP_URL in your environment file. That APP_URL will need to match the final url. So, for example, if your site is on https, you will need to ensure your APP_URL is also https.Salk
J
13

Yes! It's possible. And to do that you will have to rewrite the sendEmailVerificationNotification in your App\User. This method is provided by the Illuminate\Auth\MustVerfiyEmail trait. The method sendEmailVerificationNotification notifies the created user by sending an Email as defined in the Illuminate\Auth\Notifications\VerifyEmail Notification class.

// This is the code defined in the sendEmailVerificationNotification
public function sendEmailVerificationNotification()
{
    $this->notify(new Notifications\VerifyEmail);
}

You can change this method to not notify directly the user. You will have to define a Job which you will dispath in the sendEmailVerificationNotification method instead of notifying the created user.

In the Job class you will create a handle method where you can send the email to the user, but you must provide the $user to the Job which can be performed by passing it as a parameter to the dispatch method like this:

public function sendEmailVerificationNotification()
{
    VerifyEmail::dispatch($this);
}

$this represents the created user and the App\Jobs\VerififyEmail job (which you will create) will receive all the parameters passed to the dispatch in its __construct

The code of the VerifyEmail will look like this:

namespace App\Jobs;

use App\User;
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;

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

    protected $user;

    public function __construct(User $user)
    {
        $this->user = $user;
    }

    public function handle()
    {
        // Here the email verification will be sent to the user
        $this->user->notify(new VerifyEmail);
    }
}
Junk answered 4/10, 2018 at 11:48 Comment(3)
thank you for your reply, it works ! just had to rename Job class QueuedVerifyEmail because of double class name declaration.Ignominy
You are welcome. Even if both class have the same name because they're in different namespace App\Jobs\VerifyEmail and Illuminate\Auth\Notification\VerifyEmail It will not make any issueJunk
You could have used the same class name by aliasing Laravel's class to another name like: use Illuminate\Auth\Notifications\VerifyEmail as VerifyEmailNotification; and in the handle method $this->user->notify(new VerifyEmailNotification);. That's a bit cleaner to my opinion, but that's just nitpicking.Kassey
L
4

My solution is for if you gonna register a user manually in the controller. Laravel already created the Registered event and its listener SendEmailVerificationNotification.

-first configure queue in application in .env file update QUEUE_CONNECTION=database. for more queue documentation read https://laravel.com/docs/6.x/queues

  • publish queue table by php artisan queue:table

  • php artisan migrate

  • php artisan make:job EmailVerificationJob

  • in EmailVerificationJob.php add public variable

    public $user;

  • in EmailVerificationJob.php constructor

    public function __construct(User $user) { $this->user = $user; }

  • in EmailVerificationJob.php handle function write event(new Registered($this->user)).

  • in your controller if user created successfully add this code for job to work.

    EmailVerificationJob::dispatch($user) ->delay(now()->addSeconds(5)); here job delay for 5 seconds.

  • at the end you must start queue worker php artisan queue:work --tries=3 . here tries means how many times queue should try the job.

Update#1

this solution I used in Laravel 8.

first create SendEmailVerificationNotification notification class

php artisan make:notification SendEmailVerificationNotification

app/Notifications/SendEmailVerificationNotification.php file content will be this one. here we are going to extend Laravel default SendEmailVerificationNotification class and implement should queue

<?php

namespace App\Notifications;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;

class SendEmailVerificationNotification extends \Illuminate\Auth\Listeners\SendEmailVerificationNotification implements ShouldQueue
{
    use Queueable;
}

the last step is editing EventServiceProvider class $listen array. Comment out default notification of Registered event and add custom notification which we have created.

use App\Notifications\SendEmailVerificationNotification as QueuedSendEmailVerificationNotification;
use Illuminate\Auth\Events\Registered;
//use Illuminate\Auth\Listeners\SendEmailVerificationNotification;

protected $listen = [
        Registered::class => [
//            SendEmailVerificationNotification::class,
            QueuedSendEmailVerificationNotification::class
        ],

];

Lepore answered 30/10, 2019 at 11:55 Comment(1)
The Update#1 solution (for Laravel 8) is the right thing. Thanks.Occupy
S
-4

The solution is pretty simple:

Steps:

  1. Configure Queue Driver

  2. Go To --> Illuminate\Auth\Notifications\VerifyEmail

  3. Implement 'ShouldQueue' interface and add a trait 'Queueable' on above mentioned class i.e. 'VerifyEmail' like this:

class VerifyEmail extends Notification implements ShouldQueue{ use Queueable;

.... .... ... }

3.That's it

Path of interface & trait: use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Bus\Queueable;

Please check the docs too: https://laravel.com/docs/5.7/notifications#queueing-notifications

Squeteague answered 26/11, 2018 at 19:3 Comment(2)
Not a great idea to modify the laravel classes, that's why solutions above suggest to do it by extending and overriding.Ignominy
it is not a good idea to make changes to files in laravel vendor folder because at the next composer update command your changes on files in vendor folder will be removed.Lepore

© 2022 - 2024 — McMap. All rights reserved.