Send Account Verification Emails Using Laravel Event, Jobs & Queues

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:
- The user submits their registration details.
- The user is created in the database.
- An event is triggered, indicating that a new user has registered.
- A listener catches this event and dispatches a job to send a verification email.
- A prepared Email template is already set with a variable email-id for every new registry.
- 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
- Job Delays
- Compensate for Failures
- 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.php
inside 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 todefault
andlow-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.