Introduction
Many web applications require users to verify their email addresses before using the application. Rather than forcing you to re-implement this feature by hand for each application you create, Laravel provides convenient built-in services for sending and verifying email verification requests.
Note:
Want to get started fast? Install one of the Laravel application starter kits in a fresh Laravel application. The starter kits will take care of scaffolding your entire authentication system, including email verification support.
Model Preparation
Before getting started, verify that your
App\Models\User
model implements the
Illuminate\Contracts\Auth\MustVerifyEmail
contract:
<?php
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;
// ...
}
Once this interface has been added to your model, newly
registered users will automatically be sent an email
containing an email verification link. As you can see by
examining your application's
App\Providers\EventServiceProvider
, Laravel
already contains a
SendEmailVerificationNotification
listener that is attached to
the Illuminate\Auth\Events\Registered
event. This event listener will send the email
verification link to the user.
If you are manually implementing registration within your
application instead of using a starter kit, you
should ensure that you are dispatching the
Illuminate\Auth\Events\Registered
event
after a user's registration is successful:
use Illuminate\Auth\Events\Registered;
event(new Registered($user));
Database Preparation
Next, your users
table must contain an
email_verified_at
column to store the date
and time that the user's email address was verified. By
default, the users
table migration included
with the Laravel framework already includes this column.
So, all you need to do is run your database
migrations:
php artisan migrate
Routing
To properly implement email verification, three routes will need to be defined. First, a route will be needed to display a notice to the user that they should click the email verification link in the verification email that Laravel sent them after registration.
Second, a route will be needed to handle requests generated when the user clicks the email verification link in the email.
Third, a route will be needed to resend a verification link if the user accidentally loses the first verification link.
The Email Verification Notice
As mentioned previously, a route should be defined that
will return a view instructing the user to click the
email verification link that was emailed to them by
Laravel after registration. This view will be displayed
to users when they try to access other parts of the
application without verifying their email address first.
Remember, the link is automatically emailed to the user
as long as your App\Models\User
model
implements the MustVerifyEmail
interface:
Route::get('/email/verify', function () {
return view('auth.verify-email');
})->middleware('auth')->name('verification.notice');
The route that returns the email verification notice
should be named verification.notice
. It is
important that the route is assigned this exact name
since the verified
middleware included with Laravel
will automatically redirect to this route name if a user
has not verified their email address.
Note:
When manually implementing email verification, you are required to define the contents of the verification notice view yourself. If you would like scaffolding that includes all necessary authentication and verification views, check out the Laravel application starter kits.
The Email Verification Handler
Next, we need to define a route that will handle requests
generated when the user clicks the email verification
link that was emailed to them. This route should be
named verification.verify
and be assigned
the auth
and signed
middlewares:
use Illuminate\Foundation\Auth\EmailVerificationRequest;
Route::get('/email/verify/{id}/{hash}', function (EmailVerificationRequest $request) {
$request->fulfill();
return redirect('/home');
})->middleware(['auth', 'signed'])->name('verification.verify');
Before moving on, let's take a closer look at this route.
First, you'll notice we are using an
EmailVerificationRequest
request type
instead of the typical
Illuminate\Http\Request
instance. The
EmailVerificationRequest
is a form
request that is included with Laravel. This
request will automatically take care of validating the
request's id
and hash
parameters.
Next, we can proceed directly to calling the
fulfill
method on the request. This method
will call the markEmailAsVerified
method on
the authenticated user and dispatch the
Illuminate\Auth\Events\Verified
event. The
markEmailAsVerified
method is available to
the default App\Models\User
model via the
Illuminate\Foundation\Auth\User
base class.
Once the user's email address has been verified, you may
redirect them wherever you wish.
Resending the Verification Email
Sometimes a user may misplace or accidentally delete the email address verification email. To accommodate this, you may wish to define a route to allow the user to request that the verification email be resent. You may then make a request to this route by placing a simple form submission button within your verification notice view:
use Illuminate\Http\Request;
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');
Protecting Routes
Route middleware may be
used to only allow verified users to access a given
route. Laravel ships with a verified
middleware alias, which is an alias for the
Illuminate\Auth\Middleware\EnsureEmailIsVerified
class. Since this middleware is already registered in
your application's HTTP kernel, all you need to do is
attach the middleware to a route definition. Typically,
this middleware is paired with the auth
middleware:
Route::get('/profile', function () {
// Only verified users may access this route...
})->middleware(['auth', 'verified']);
If an unverified user attempts to access a route that has
been assigned this middleware, they will automatically
be redirected to the verification.notice
named
route.
Customization
Verification Email Customization
Although the default email verification notification should satisfy the requirements of most applications, Laravel allows you to customize how the email verification mail message is constructed.
To get started, pass a closure to the
toMailUsing
method provided by the
Illuminate\Auth\Notifications\VerifyEmail
notification. The closure will receive the notifiable
model instance that is receiving the notification as
well as the signed email verification URL that the user
must visit to verify their email address. The closure
should return an instance of
Illuminate\Notifications\Messages\MailMessage
.
Typically, you should 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);
});
}
Note:
To learn more about mail notifications, please consult the mail notification documentation.
Events
When using the Laravel
application starter kits, Laravel dispatches events during the email
verification process. If you are manually handling email
verification for your application, you may wish to
manually dispatch these events after verification is
completed. You may attach listeners to these events in
your application's
EventServiceProvider
:
use App\Listeners\LogVerifiedUser;
use Illuminate\Auth\Events\Verified;
/**
* The event listener mappings for the application.
*
* @var array
*/
protected $listen = [
Verified::class => [
LogVerifiedUser::class,
],
];