Updated on May 8, 2023.
When a new user clicks on the Sign-up button of an app, they usually get a confirmation email with an activation link. This is needed to make sure that the user owns the email address entered during the sign-up. After they click on the activation link, the user is authenticated for the app.
From the user’s standpoint, the email verification process is quite simple. From the developer’s perspective, things are much trickier unless your app is built with Laravel. Those who use Laravel 5.7+ have the user email verification available out-of-the-box. For earlier releases of the framework, you can use a dedicated package to add email verification to your project. However, most of those packages are no longer maintained and could have significant security vulnerabilities.
So, in this article, we’ll detail how to do email verification automatically and manually in newer versions of Laravel. We’ll also discuss some customization options. Let’s begin.
Basic project to be used as an example
Since email verification requires one to send emails in Laravel, let’s create a basic project with all the stuff needed for that. Here is the first command to begin with:
composer create-project --prefer-dist laravel/laravel app
Now, let’s create a database using the mysql
client and then configure the .env file thereupon:
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=DB-laravel
DB_USERNAME=root
DB_PASSWORD=root
Run the migrate
command to create tables for users, password resets, and failed jobs:
php artisan migrate
Since our Laravel app will send a confirmation email, we need to set up the email configuration in the .env file.
For email testing purposes, we’ll use Mailtrap Email Testing, an Email Sandbox that captures SMTP traffic from staging and allows developers to debug emails without the risk of spamming users.
The Email Sandbox is one of the SMTP drivers in Laravel. All you need to do is sign up and add your credentials to .env, as follows:
MAIL_MAILER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=<********> //Your Mailtrap username
MAIL_PASSWORD=<********> //Your Mailtrap password
MAIL_ENCRYPTION=tls
For more on Mailtrap features and functions, read the Mailtrap Getting Started Guide.
Scaffold UI
In the latest release of the framework it is possible to use several starter kits to scaffold the UI for registration, login and forgot password. We will use Laravel Breeze which includes all authentication features such as login, registration, password reset, email verification, and password confirmation.
You can install Laravel Breeze using composer: composer require laravel/breeze --dev
The next step is to run php artisan breeze:install
– this command will publish the code (views, routes, controllers) to your application.
Finally, you will need to run migrations and install frontend assets:
php artisan migrate
npm install
npm run dev
Now you can navigate to /login
and /register routes
.
Set up email verification in Laravel 10 using the MustVerifyEmail
contract
The Must Verify Email contract is a feature that allows you to send email verification in Laravel by adding a few lines of code to the following files:
App/User.php:
Implement the MustVerifyEmail
contract in the User
model:
<?php
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable implements MustVerifyEmail
{
use Notifiable;
protected $fillable = [
'name', 'email', 'password',
];
protected $hidden = [
'password', 'remember_token',
];
}
routes/web.php
Add routes such as email/verify
, email/verify/{id}/{hash}
, and email/verification-notification
to the app:
use Illuminate\Http\Request;
use Illuminate\Foundation\Auth\EmailVerificationRequest;
Route::get('/email/verify', function () {
return view('auth.verify-email');
})->middleware('auth')->name('verification.notice');
Route::get('/email/verify/{id}/{hash}', function (EmailVerificationRequest $request) {
$request->fulfill();
return redirect('/dashboard);
})->middleware(['auth', 'signed'])->name('verification.verify');
Route::post('/email/verification-notification', function (Request $request) {
$request->user()->sendEmailVerificationNotification();
return back()->with('message', 'Verification link sent!');
})->middleware(['auth', 'throttle:6,1'])->name('verification.send');
Now you can test the app.
And that’s what you’ll see in the Mailtrap Demo inbox:
Customization
In the screenshots above, the default name of the app, Laravel, is used as the sender’s name. You can update the name in the .env file:
APP_NAME=<Name of your app>
To customize notifications, you need to call the toMailUsing
method from the boot method of your application’s App\Providers\AuthServiceProvider
class.
use Illuminate\Auth\Notifications\VerifyEmail;
use Illuminate\Notifications\Messages\MailMessage;
/**
* Register any authentication / authorization services.
*/
public function boot(): void
{
// ...
VerifyEmail::toMailUsing(function (object $notifiable, string $url) {
return (new MailMessage)
->subject('Verify Email Address')
->line('Click the button below to verify your email address.')
->action('Verify Email Address', $url);
});
}
For more on sending Laravel email notifications, read our dedicated blog post.
How can I manually verify users?
The MustVerifyEmail
class is a great thing to use. However, you may need to take over the control and manually verify email addresses without sending emails. Why would anyone do so? Reasons may include a need to create and add system users that have no accessible email addresses, import a list of email addresses (verified) to a migrated app, and others.
So, each manually created user will see the following message when signing in:
The problem lies in the timestamp in the Email Verification Column (email_verified_at
) of the user
table. When creating users manually, you need to validate them by setting a valid timestamp. In this case, there will be no email verification requests. Here is how you can do this:
markEmailAsVerified()
The markEmailAsVerified()
method allows you to verify the user after it’s been created. Check out the following example:
$user = User::create([
'name' => 'John Doe',
'email' => 'john.doe@example.com',
'password' => Hash::make('password')
]);
$user->markEmailAsVerified();
forceCreate()
The forceCreate()
method can do the same but in a slightly different way:
$user = User::forceCreate([
'name' => 'John Doe',
'email' => john.doe@example.com',
'password' => Hash::make('password'),
'email_verified_at' => now() //Carbon instance
]);
Manually set a valid timestamp
The most obvious way is to set a valid timestamp in the email_verified_at
column. To do this, you need to add the column to the $fillable
array in the user
model. For example, like this:
protected $fillable = [
'name', 'email', 'password', 'email_verified_at',
];
After that, you can use the email_verified_at
value within the create
method when creating a user:
$user = User::create([
'name' => 'John Doe',
'email' => john.doe@example.com',
'password' => Hash::make('password'),
'email_verified_at' => now() //Carbon instance
]);
Laravel queuing for email verification
The idea of queuing is to dispatch the processing of particular tasks, in our case, email sending, until a later time. This can speed up processing if your app sends large amounts of emails. It would be useful to implement email queues for the built-in Laravel email verification feature. The simplest way to do that is as follows:
- Create a new notification, e.g.,
CustomVerifyEmailQueued
, which extends the existing one,VerifyEmail
. Also, the new notification should implement theShouldQueue
contract. This will enable queuing. Here is how it looks:
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Auth\Notifications\VerifyEmail;
class CustomVerifyEmailQueued extends VerifyEmail implements ShouldQueue
{
use Queueable;
}
- Then override
sendEmailVerificationNotification
on theUser
model, just like we did in the Customization block above.
public function sendEmailVerificationNotification()
{
$this->notify(new \App\Notifications\CustomVerifyEmailQueued);
}
We did not touch upon the configuration of the queue driver here, which is “sync” by default without actual queuing. If you need some insight on that, check out this guide to Laravel email queues.
To wrap up
Sending a verification email is the most reliable way to check the validity of an email address. The steps above will help you implement this feature in your Laravel app. If you have another app that doesn’t use Laravel but runs on PHP, make sure to check out our YouTube tutorial on the topic:
For verifying a large number of existing addresses, you do not have to send a test email to each of them. There are plenty of online email validators that will do the job for you. In the most extreme case, you can validate an email address manually with mailbox pinging. For more on this, read this blog post.