Build Laravel 5.7 Email Authentication with Mailgun and Digital Ocean

Connor Leech
Dec 13, 2018 · 6 min read

Build session authentication with email verification into a default Laravel 5.7 app

Image for post
Image for post
Mailgun integrates with default Laravel applications

The newly released Laravel version 5.7 adds a new capability to verify user’s emails. If you’ve ever ran php artisan make:auth within a Laravel app you’ll know the feeling of pleasure and excitement when you see all of your register and login pages, complete with password hashing and a users table already built out. This excitement will soon subside after deploying to production only to find that anyone can register with garbage@notrealemail.com or whatever they feel like typing in. This thin session authentication layer doesn’t help much in a live application. The introduction of Laravel 5.7’s MustVerifyEmail interface adds to the authentication scaffold so that in order for users to login they must use a real, valid email address.

Source code on GitHub

The first step is to create a new application with some setup:

$ laravel new email-verification-example
$ php artisan make:auth
Authentication scaffolding generated successfully.
$ touch database/database.sqlite

This will create the default Laravel 5.7 app with the authentication scaffold and a file for a SQLite database. Update your .env file to point to the full path of the SQLite file:

DB_CONNECTION=sqlite
DB_DATABASE=/full/path/to/email-verification-example/database/database.sqlite

Let’s inspect the default auth scaffold and see what changes need to be made to add email verification.

You can view the Laravel Email Verification docs

The first step is to implement the MustVerifyEmail interface. An interface in PHP specifies the methods a class must implement.

<?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
{
...

That interface enforces that we have three new methods on our User model:

  • hasVerifiedEmail()
  • markEmailAsVerified()
  • sendEmailVerificationNotification()

The implementations for these methods can be found in vendor/laravel/framework/src/Illuminate/Auth/MustVerifyEmail.php. To mark a user as verified we need to have a email_verified_at column on our users table, which is already provided in our default create users table migration:

Schema::create('users', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});

Run the migrations to create the table: php artisan migrate

In the routes/web.php file update the authentication routes to include email verification:

Auth::routes(['verify' => true]);

To view all the routes available to your application you can run php artisan route:list. That’s pretty much all we need to do from the Laravel side to verify emails. If you try it now though, it won’t work:

Image for post
Image for post
Error: Expected response code 250 but got code “530”, with message “530 5.7.1 Authentication required “

Before we can send emails from our PHP server we need to configure a mail driver within Laravel.

You can check though using tinker to see that a user was created with an email_verified_at of null.

$ php artisan tinker
Psy Shell v0.9.9 (PHP 7.1.7 — cli) by Justin Hileman
>>> $users = App\User::all();

Be sure to consult the Laravel docs on sending Email

Image for post
Image for post
Mailgun logo

Mailgun offers the ability to send emails via SMTP server or over their API. In this tutorial we’re going to send emails via the Mailgun API. It’s faster, scales better and takes less work to setup than configuring SMTP.

Image for post
Image for post
How to Start Sending Email from the Mailgun docs

We’re going to be sending API calls. For that we need Guzzle

$ composer require guzzlehttp/guzzle

In order for our application to send emails we need a hosted domain name. I have a domain name that I bough through Google Domains for about $12/year. The site (https://employbl.com/) is hosted on Laravel Forge for a monthly fee. To get it deployed I followed the Laracasts course, Learn Laravel Forge:

Image for post
Image for post
Learn Laravel Forge series on Laracasts

In that course I set up my Laravel application to run off Digital Ocean droplets. In that process I configured my Google Domain name to point to Digital Ocean like so:

Image for post
Image for post
Instead of Google’s DNS servers I am using Digital Ocean’s.

So even though I bought my domain name through Google Domains I configured my domain name server on the Digital Ocean side.

If you’re interested in how to hook up a custom domain to Laravel Forge I recommend this (free) video.

Once you’ve created a Mailgun account, you’ll need to verify your domain, which takes about 24 hours.

To do that, we need to add two TXT records and one CNAME record. I opted to NOT add MX records because I have a Gmail account that uses my domain for sending a receiving emails. To find these records go to the domain in your Mailgun account and check Domain Verification & DNS.

Once you have a working Mailgun domain, head to the dashboard to find your API key. Update the .env file accordingly:

MAIL_DRIVER=mailgun
MAILGUN_DOMAIN=mg.YOUR_DOMAIN.com
MAILGUN_SECRET=YOUR_KEY_HERE

Once email sending is configured, after a user registers they will see a landing paging asking them to check their email. This page can be modified in resources/views/auth/verify.blade.php.

Image for post
Image for post
Landing page if user has not verified their email.

That will send a real email to the address you provided. The template for this email exists in Illuminate\Auth\Notifications\VerifyEmail.php.

Image for post
Image for post
Default verification email sent to the user after they register.

If we don’t want our verification emails to say “Regards” or the above text then we need to customize them. You can publish the default templates using the below publish commands:

$ php artisan vendor:publish --tag=laravel-notifications
$ php artisan vendor:publish --tag=laravel-mail

Then write the new defaults in resources/views/vendor/notifications/email.blade.php. If you have more to change you could re-implement the notification by adding a new sendEmailVerificationNotification method to your User model that returns a custom notification that you make.

Once the user clicks the Verify Email Address link they’ll be redirected to their dashboard able to login without issue.

Image for post
Image for post
Dashboard once user has verified their email.

That should have you going! The most difficult part for me was getting the mail server and Mailgun configured. After your domain is verified and Mailgun is all set up the Laravel part ends up being straightforward.

Have you been able to get up and running? Is anyone using this functionality in production yet? Hit me up on Twitter or leave comments below.

I found these tutorials, in addition to the links above to be very helpful.

🚀 If you’re a candidate on the job market or startup looking to hire in the Bay Area, feel free to create a profile on Employbl 🤝

Employbl

Find a tech or startup job in the Bay Area.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store