Send Account Verification Emails Using Laravel Event, Jobs & Queues

Mohammed Muwanga
9 min readFeb 3, 2025
Send Account Verification Emails Using Laravel Event, Jobs and Queues — Muwanga Mohammed — Web design and development

For many online systems, there will always be a need to register your visitors and retain them as active system users, right! Now, whenever you’re developing a Laravel application with such a capability of retaining specific user’s information, an account will have to be created. In this case, using an email address as a unique identifier and form of communication simplifies our implementation as programmers. In one way or another, you’ll end up looking for away to automatically verify that email address for security concerns. What’s the best solution currently for such cases?

Thanks to Laravel Events, Jobs and Queues. They allow you to send that verification link to the user by setting a background job to specified queue when a registration event is fired. This approach simplifies the signup process to a smooth and fast as well as welcoming user experience which is desired by all system end users.

Let me hope we are all on the same page, otherwise let’s elaborate this with a real scenario based system — you can call it a case study.

Case Study: Online Office Furniture Store System

Whenever a new user signs up for updates from an online Dubai office furniture store, you as a web designer of the system, its ethical to verify and validate any email address kept in the system’s database. So, you’ll typically want to send them a verification email in order let them confirm their email address. Then after, you can send them updates about ergonomic chairs, executive desks, workstations and some lounge chairs.

Here are the steps

Following User Signup Process

During a new user sign up, the following steps have to occur:

  1. The user submits their registration details.
  2. The user is created in the database.
  3. An event is triggered, indicating that a new user has registered.
  4. A listener catches this event and dispatches a job to send a verification email.
  5. A prepared Email template is already set with a variable email-id for every new registry.
  6. The job sends the email in the background using Laravel queue system.

Step-by-Step Implementation of Sending Account Verification.

while your Laravel application is open in an up-to-date IDE like VS-Code or IntelliJ Idea

Step 1: Create the Event

First, open your terminal then create an event that will be triggered after a user successfully registers.

php artisan make:event UserRegistered

After that command, an event class UserRegistered is created in the app/Events/ directory. As of Laravel 11, the event looks like this:

namespace App\Events;

use App\Models\User;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

class UserRegistered
{
use Dispatchable, SerializesModels;

public $user;

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

Step 2: Create the Listener

Next, create a listener the same way for handling the event by dispatching a job to send the verification email.

php artisan make:listener SendVerificationEmail --event=UserRegistered

This will generate for you a SendVerificationEmail listener in the app/Listeners/ directory. In the listener, you dispatch a job to send the email:

namespace App\Listeners;

use App\Events\UserRegistered;
use App\Jobs\SendEmailVerificationJob;

class SendEmailVerificationListener
{
public function handle(UserRegistered $event)
{
dispatch(new SendEmailVerificationJob($event->user));
}
}

Step 3: Register the Event and Listener

In the EventServiceProvider, register the event and listener:

namespace App\Providers;

use App\Events\UserRegistered;
use App\Listeners\SendVerificationEmail;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;

class EventServiceProvider extends ServiceProvider
{
protected $listen = [
UserRegistered::class => [
SendVerificationEmail::class,
],
];

public function boot()
{
parent::boot();
}
}

Step 4: Trigger the Event in the Controller

When a user signs up, trigger the UserRegistered event in the controller:

namespace App\Http\Controllers\Auth;

use App\Models\User;
use App\Events\UserRegistered;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;

class RegisterController extends Controller
{
public function register(Request $request)
{
// Validate the request and create the user
$data = $request->validate([
'name' => 'required|string|max:255',
'email' => 'required|string|email|max:255|unique:users',
'password' => 'required|string|min:8|confirmed',
]);

// Create the user
$user = User::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => bcrypt($data['password']),
]);

// Fire the UserRegistered event
event(new UserRegistered($user));

// Redirect or return a response
return redirect()->route('home')->with('status', 'We have sent you a verification email!');
}
}

5. Create the Job for Sending Verification Emails

First, you need to create a job that will handle the task of sending the verification email. You can generate a job using the following Artisan command:

php artisan make:job SendVerificationEmailJob

This command will create a job class in the App\Jobs directory. Next, you’ll define the logic for sending the email inside the handle method of the job.

namespace App\Jobs;

use App\Models\User;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Mail;
use App\Mail\VerificationEmail;

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

public $user;

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

public function handle()
{
Mail::to($this->user->email)->send(new VerificationEmail($this->user));
}
}

In this example, the SendVerificationEmailJob job is responsible for sending the email to the new user. The job uses Laravel’s Mail facade to send an email based on a mailable class (VerificationEmail).

Step 6: Create the Mailable Class

To create the VerificationEmail mailable class that will be used to structure the email content, run the following command:

php artisan make:mail VerificationEmail

This command will create a mailable class in the App\Mail directory. You can customize the email content within this class:

namespace App\Mail;

use App\Models\User;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;

class VerificationEmail extends Mailable
{
use Queueable, SerializesModels;

public $user;

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

public function build()
{
return $this->subject('Verify Your Email Address')
->view('emails.verify')
->with([
'verificationUrl' => url('/email/verify/'.$this->user->id.'/'.sha1($this->user->email))
]);
}
}

Now, create the email view at resources/views/emails/verify.blade.php

<!DOCTYPE html>
<html>
<head>
<title>Verify Your Email</title>
</head>
<body>
<h2>Welcome, {{ $user->name }}</h2>
<p>Click the button below to verify your email address:</p>
<a href="{{ $verificationUrl }}" style="background-color: #3490dc; color: white; padding: 10px 15px; text-decoration: none; border-radius: 5px;">Verify Email</a>
<p>If you did not register, no further action is required.</p>
</body>
</html>

Step 7: Configure Mail Driver

Update .env and make sure it contains:

MAIL_MAILER=smtp
MAIL_HOST=smtp.example.com
MAIL_PORT=587
MAIL_USERNAME=example_email@officefurniture.com
MAIL_PASSWORD=password_1234
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS=your_email@example.com
MAIL_FROM_NAME="Your App Name"

Step 8: Set Up Email Verification Routes

Modify web app routes in routes/web.php. Remember to take full advantage of Laravel context capabilities like the middleware for access control.

use Illuminate\Foundation\Auth\EmailVerificationRequest;
use Illuminate\Http\Request;

// Email verification notice
Route::get('/email/verify', function () {
return response()->json(['message' => 'Verify your email address.']);
})->middleware('auth')->name('verification.notice');

// Email verification handler
Route::get('/email/verify/{id}/{hash}', function (EmailVerificationRequest $request) {
$request->fulfill();
return response()->json(['message' => 'Email verified successfully.']);
})->middleware(['auth', 'signed'])->name('verification.verify');

// Resend verification email
Route::post('/email/resend', function (Request $request) {
$request->user()->sendEmailVerificationNotification();
return response()->json(['message' => 'Verification email resent.']);
})->middleware(['auth', 'throttle:6,1'])->name('verification.resend');

Step 9: Make sure User Model Uses Email Verification

Modify app/Models/User.php as MustVerifyEmail

namespace App\Models;

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

class User extends Authenticatable implements MustVerifyEmail
{
use Notifiable;

protected $fillable = ['name', 'email', 'password'];
}

Step 10: Configure Laravel Queue for Asynchronous Processing

Make sure your queue is configured in the .env file, and set up queue driver:

QUEUE_CONNECTION=database

Run the migrations to create the necessary tables for the database queue:

php artisan queue:table
php artisan migrate

Step 10. Running the Queue Worker

To process the queued job, you need to run the queue worker. Use this Artisan command in your terminal;

php artisan queue:work

This command starts the worker that listens to the queue and processes the SendVerificationEmail job. If you’re deploying this on a live server, you might want to run the worker as a daemon or set up a supervisor to manage the process.

Does Your Setup Really Work?

How do you know with out Testing — Unit and Integration testing?

Finally Test Your Email Verification Application

  • Register a new user via API or form submission.
  • Check your email inbox for the verification email.
  • Click the link to verify the email.
  • Check php artisan queue:work logs to confirm the job execution.

Why This Approach?

Event-Driven Architecture → Keeps the application modular and scalable.
Listener to Dispatch Jobs → Ensures the process is queued and non-blocking.
Job & Queue Handling → Reduces load time for the user during registration.

Now, your Laravel application efficiently sends email verification using events, listeners, jobs, and queues! 🚀

Advanced Considerations for Reliability

  1. Job Delays
  2. Compensate for Failures
  3. Queue Prioritization

Job Delays:

If you want to delay the sending of the verification email, you can use the delay method when dispatching the job. Modify the code in the Event Listener file located at app/Listeners/SendEmailVerificationListener.phpinside the handle()method.

namespace App\Listeners;

use App\Events\UserRegistered;
use App\Jobs\SendVerificationEmailJob;

class SendEmailVerificationListener
{
public function handle(UserRegistered $event)
{
SendVerificationEmailJob::dispatch($event->user)->delay(now()->addMinutes(5));
}
}

What Happens Here?

  • The UserRegistered event is fired when a new user registers.
  • The SendEmailVerificationListener listens for this event.
  • Instead of sending the email immediately, it dispatches the job with a 5-minute delay.
  • Laravel’s queue worker processes the job after 5 minutes, ensuring smoother user experience.

This method ensures that your email verification does not block user registration and gets processed asynchronously.

Handling Failures

In case of any failures, such as issues with the mail server, Laravel has a strategy for handling such failures in queued jobs. This actually ensures that failed emails do not go unnoticed and can be retried or logged for debugging.

You can define a failed() method inside the SendVerificationEmailJob class to log failures or notify admins.

Updated SendVerificationEmailJob.php

namespace App\Jobs;

use App\Models\User;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Mail;
use App\Mail\VerificationEmail;
use Illuminate\Support\Facades\Log;

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

public $user;

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

public function handle()
{
Mail::to($this->user->email)->send(new VerificationEmail($this->user));
}

/**
* Handle job failure.
*/

public function failed(\Exception $exception)
{
Log::error('Verification email failed for user: ' . $this->user->email, [
'error' => $exception->getMessage()
]);

// Optionally, notify an admin via email
Mail::raw("Email verification failed for {$this->user->email}: {$exception->getMessage()}", function ($message) {
$message->to('admin@example.com')
->subject('Email Verification Job Failed');
});
}
}

Otherwise;

Consider automatic job retries. By default, Laravel retries failed jobs three times before marking them as failed. You can customize this by adding --tries when running the queue worker:

php artisan queue:work --tries=5

Alternatively, you can set the maximum retry count per job:

class SendVerificationEmailJob implements ShouldQueue
{
public $tries = 5; // Retries 5 times before marking as failed
}

You can also store the Failed Jobs in the Database. In this case, persist failed jobs and retry them later. That means You Create a Failed Jobs Table by running migrations

php artisan queue:failed-table
php artisan migrate

If all fails, don’t hesitate to notify the user about failing to sending them the link, but this is optional.

use Illuminate\Support\Facades\Notification;
use App\Notifications\EmailVerificationFailed;

public function failed(\Exception $exception)
{
$this->user->notify(new EmailVerificationFailed());
}

Queue Prioritization

There are cases when we have multiple queues and want to prioritize the sending of verification emails. This means they’re to be processed immediately. Just like in our online office furniture system, this prevents delays caused by less critical jobs like generating monthly sales reports or logging.

Assigning High Priority to Email Verification Jobs

Modify the SendVerificationEmailJob.php file to place email verification jobs in a high-priority queue:

class SendVerificationEmailJob implements ShouldQueue
{
public $queue = 'high-priority';

public function handle()
{
Mail::to($this->user->email)->send(new VerificationEmail($this->user));
}
}

Alternatively, set the queue when dispatching the job:

SendVerificationEmailJob::dispatch($user)->onQueue('high-priority');

Run Workers for Prioritized Queues

To ensure email verification jobs are processed before other queued tasks, start the queue worker with priority ordering:

php artisan queue:work --queue=high-priority,default,low-priority

Setting them in this order, the worker first processes high-priority (email verification). Then, it moves to default and low-priority jobs.

Why Prioritize Email Verification?

Prevents delays in user verification
Ensures a seamless onboarding experience
Avoids email congestion from less important jobs
Optimizes queue performance in high-traffic applications

Conclusion

Using Laravel Jobs and Queues for sending verification emails in your online systems like we have used in an office furniture system, you enhance the user experience. In fact, you also ensure that resource-intensive tasks are handled in the background. This approach keeps your application responsive and efficient, allowing you to scale as your user base grows. Even if it’s sending a simple verification email or processing complex tasks, Laravel Jobs and Queues provide a robust and flexible way to manage background processing in your application.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

Mohammed Muwanga
Mohammed Muwanga

Written by Mohammed Muwanga

Web Design, Development, SEO and Ergonomics

No responses yet

Write a response