[Laravel]メール認証を使った会員登録

今回は、Laravel5(5.6)にてメール認証を行った会員登録の実装を紹介します。

実務でLaravelのサイトを作ったときメール認証の実装方法が日本語で解説されていないと感じたので。
手順は良いからソース知りたいって人→[ココ](https://github.com/nitaking/email-verify)

## 実装機能
1. 仮会員登録
2. メール認証
2. 本会員登録

## 流れ
1. 仮会員としてメールアドレスを登録
2. 本会員登録用URLを添付したメール送信
3. URLクリックで入力フォームへ（メール認証）
4. 本会員情報の入力
4. 本会員登録完了

## 画面の流れ
今回は、以下の画面構成で考えました。

1. 仮会員登録画面
2. 確認画面
3. 完了画面
4. （仮会員登録認証メール）
5. 本会員登録画面
6. 確認画面
7. 完了画面


## 実装
さて、実装に入りましょう。

### 仮会員登録

まだ、`make:auth`を実行していない方は先に実行してください。

```sh
php artisan make:auth
```
実行済みの方は、次に進みます。

### Usersテーブルにtokenを追加する
仮会員登録で発行するURLtokenのフィールドを、`Users`テーブルに追加します。

Artisanコマンドでmigrationファイルを作成しましょう。

```sh

php artisan make:migration add_columns_users_table
```
> 補足：`--table`オプションでテーブル名を指定してもいいです。
```
php artisan make:migration add_votes_to_users_table --table=users
```

作成したmigrationファイルに2カラム追加します。
1. email_verified : 認証済みかどうか
2. email_token : email用トークン

スキーマの内容は以下のようにします。

```php

class AddColumnsUsersTable extends Migration
{
    public function up()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->tinyInteger('email_verified')->default(0);
            $table->string('email_verify_token')->nullable();
        });
    }

    public function down()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->dropColumn('email_verified');
            $table->dropColumn('email_verify_token');
        });
    }
}

```

> 重要：`down()`に記述を忘れずに入力してください。`migrate:rollback`コマンドを実行したとき、down()の処理を行います。up()に対する逆の処理がdown()に正しく記載されていない場合、`migrate:rollback`と`migrate:reset`が失敗してしまいます。

migrationファイルの作成が終わったら、忘れずに`migrate`コマンドでmigrationの適用をしてください。

> 追記： tinyIntegerはbooleanでもいいです。そちらのほうが自然かも

```
php artisan migrate
```

#### .envファイルの変更
.envファイルにemail設定を追加します。
ここでは、mailtrapを使用して実装しています。
アカウントを作るだけなので簡単です。詳しくはこちら[MailtrapでLaravelの簡単メール送信テスト](https://qiita.com/ubonsa/items/5514fb9c5d5783bcc758)などを参考にしてください。

.envファイルは以下のように修正します。

```diff:　.env
MAIL_DRIVER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=fec77971a86b66
MAIL_PASSWORD=9c480963d8d7df
MAIL_ENCRYPTION = tls
+ MAIL_FROM_ADDRESS=from@example.com
+ MAIL_FROM_NAME=LaravelExampler
```

1. MAIL_FROM_ADDRESS
2. MAIL_FROM_NAME

上記を追加することで、メール送信処理のアドレスと送信者名のデフォルト値を設定することができます。

#### メール作成
認証メールに使用するviewと、tokenを返すクラスを作成します。

```
php artisan make:mail EmailVerification
```

このコマンドで、`app/Mail`にMailableを継承したEmailVerificationクラスが作成されます。
このクラスにメール送信に使用するviewやメールタイトルなどの設定を記述することになります。

#### EmailVerificationの設定
このクラスには２つのメソッドがあります。

1. constructor()
2. build()

コンストラクタはご存知の通りです。buildは実行時に呼ばれる関数です。

コンストラクタに、Users情報を渡しましょう。

クラス変数を追加します。

```php
protected $user;
```

constructor()で引数に$userを設定し、クラス変数にセットします。

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

> 補足：こうすることで、build()にて`$this->user->email_verify_token`と参照することができます。（ユーザーごとのtokenを判別できます）

build()を更新します。

```php
    public function build()
    {
        return $this
            ->subject('【site】仮登録が完了しました')
            ->view('auth.email.pre_register')
            ->with(['token' => $this->user->email_verify_token,]);
    }
}
```

これで、viewと一緒にtokenを渡すことができました！

#### Emailテンプレートの作成
さて、今度はEmailの本文となるviewを作りましょう。

今回は`views/auth/email`ディレクトリに`pre_register.blade.php`を作成しました。（イケてるファイル名に差し替えて使ってください。）

```php
サイトへのアカウント仮登録が完了しました。<br>
<br>
以下のURLからログインして、本登録を完了させてください。<br>
{{url('register/verify/'.$token)}}
```


#### Userモデルの更新
Userに追加したカラムにデータをセットするには、一手間いります。
Laravelでは、モデルへのカラムへの挿入時には`$fillable`もしくは`$guarded`にカラムを設定する必要があります。
> 詳しくはこちらなどを参照ください：
> [【Laravel：Eloquentクラス】fillableとguardedの指定はどちらかだけでいい](https://qiita.com/kk_take/items/3e0639ed605f74c34619)

それでは`User.php`へ追加したカラムを`$fillable`に設定しましょう。

```diff
    protected $fillable = [
        'name', 'email', 'password',
+        'email_verified', 'email_verify_token',
    ];
```

#### 仮会員登録フォームの追加
仮会員登録時に「メールアドレス」「パスワード」の登録を行う仕様にします。
make:authで作成したものは「名前」が入っているので取り除きましょう。

`register.blade.php`から名前の項目を削除します。

```diff
-                        <div class="form-group row">
-                            <label for="name" class="col-md-4 col-form-label text-md-right">{{ __('Name') }}</label>
-
-                            <div class="col-md-6">
-                                <input id="name" type="text" class="form-control{{ $errors->has('name') ? ' is-invalid' : '' }}" name="name" value="{{ old('name') }}" required autofocus>
-
-                                @if ($errors->has('name'))
-                                    <span class="invalid-feedback">
-                                        <strong>{{ $errors->first('name') }}</strong>
-                                    </span>
-                                @endif
-                            </div>
-                        </div>
```

`register.blade.php`のformの送信先を変更します。

```diff
-                    <form method="POST" action="{{ route('register') }}">
+                    <form method="POST" action="{{ route('register.pre_check') }}">

```
![image](https://user-images.githubusercontent.com/10850034/40029895-0482dc1a-5822-11e8-8281-5a5b40f38968.png)

### 仮会員確認

次に、仮登録確認画面のviewを追加しましょう。

`views/auth`に`register_check.blade.php`を追加します。

```php:register_check.blade.php
@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row justify-content-center">
        <div class="col-md-8">
            <div class="card">
                <div class="card-header">仮会員登録確認</div>

                <div class="card-body">
                    <form method="POST" action="{{ route('register') }}">
                        @csrf

                        <div class="form-group row">
                            <label for="email" class="col-md-4 col-form-label text-md-right">メールアドレス</label>

                            <div class="col-md-6">
                                <span class="">{{$email}}</span>
                                <input type="hidden" name="email" value="{{$email}}">
                            </div>
                        </div>

                        <div class="form-group row">
                            <label for="password" class="col-md-4 col-form-label text-md-right">パスワード</label>

                            <div class="col-md-6">
                                <span class="">{{$password_mask}}</span>
                                <input type="hidden" name="password" value="{{$password}}">
                            </div>
                        </div>

                        <div class="form-group row mb-0">
                            <div class="col-md-6 offset-md-4">
                                <button type="submit" class="btn btn-primary">
                                    仮登録
                                </button>
                            </div>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
@endsection
```

`web.php`（route）に追加します。

```
Route::post('register/pre_check', 'Auth\RegisterController@pre_check')->name('register.pre_check');
```

#### RegisterControllerの更新
「名前」を削除したので、Controllerに反映しましょう。
`Validator()`から`'name'`の行を削除してください。

```diff
    protected function validator(array $data)
    {
        return Validator::make($data, [
-            'name' => 'required|string|max:255',
            'email' => 'required|string|email|max:255|unique:users',
            'password' => 'required|string|min:6|confirmed',
        ]);
    }
```
削除しないままだと、存在しない項目のバリデーションが実行されることになります。

次に、確認画面のビューに遷移できるように修正しましょう。
web.phpに記載したメソッド：`pre_check()`を追加し、returnにviewを返します。
ここでは、受け取ったリクエストのバリデーションチェックを行い、ビューに値を渡します。
passwordは、表示するときにマスキングするようにしています。

```php:RegisterController.php
    public function pre_check(Request $request){
        $this->validator($request->all())->validate();
        //flash data
        $request->flashOnly( 'email');

        $bridge_request = $request->all();
        // password マスキング
        $bridge_request['password_mask'] = '******';

        return view('auth.register_check')->with($bridge_request);
    }
```

これで、仮会員登録画面〜確認画面までが実装できました。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103475/c42b9104-876c-774b-a7c7-5e82f3221914.png)


#### 仮登録完了画面の追加

`views/auth`に`registered.blade.php`を追加してください。

```php:registered.blade.php
@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row justify-content-center">
        <div class="col-md-8">
            <div class="card">
                <div class="card-header">仮会員登録完了</div>

                <div class="card-body">
                    <p>この度は、ご登録いただき、誠にありがとうございます。</p>
                    <p>
                        ご本人様確認のため、ご登録いただいたメールアドレスに、<br>
                        本登録のご案内のメールが届きます。
                    </p>
                    <p>
                        そちらに記載されているURLにアクセスし、<br>
                        アカウントの本登録を完了させてください。
                    </p>
                </div>
            </div>
        </div>
    </div>
</div>
@endsection
```

RegisterControllerの`create()`に`email_verify_token`を追加します。
ここで、作成した`EmailVerification`を使用し、`Mail::`を使用してメール送信処理を実行します。

```diff
    protected function create(array $data)
    {
-        return User::create([
-            'email' => $data['email'],
-            'password' => Hash::make($data['password']),
-        ]);

+        $user = User::create([
+            'email' => $data['email'],
+            'password' => Hash::make($data['password']),
+            'email_verify_token' => base64_encode($data['email']),
+        ]);

+        $email = new EmailVerification($user);
+        Mail::to($user->email)->send($email);

+        return $user;
    }
```

`/register`で呼ばれるメソッド`register()`に上記の`create()`メソッドを紐づけます。

```php
    public function register(Request $request)
    {
        event(new Registered($user = $this->create( $request->all() )));

        return view('auth.registered');
    }
```
> 補足：`/register`は、make:authコマンドで`web.php`に作成される、`Auth::routes()`に含まれています。
> 確認したい場合は、`php artisan route:list`コマンドを実行してみてください。


今のままだと、UsersテーブルのnameがNot nullになっているのでエラーになってしまいます。
`name`に`nullable`を設定しましょう。

```
php artisan make:migration change_column_users_table --table=users
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103475/3b512922-ce8f-295c-0ab1-cb3c6dabe1b1.png)


ここまでで、仮会員登録が実装できました。
うまくできないときは、こちらの[ソース](https://github.com/nitaking/email-verify/tree/v0.1)と比較して見てください

### 本会員登録フォームの追加

本会員登録用URLがクリックされると本会員登録フォームに遷移されるようにしましょう。
ルーティング(web.php)に以下を追加します。

```php
Route::get('register/verify/{token}', 'Auth\RegisterController@showForm');
```

RegisterControllerに`showForm()`を追加しましょう。
エラーチェックをした後、Viewを返す処理をしています。

```php
    public function showForm($email_token)
    {
        // 使用可能なトークンか
        if ( !User::where('email_verify_token',$email_token)->exists() )
        {
            return view('auth.main.register')->with('message', '無効なトークンです。');
        } else {
            $user = User::where('email_verify_token', $email_token)->first();
            // 本登録済みユーザーか
            if ($user->status == config('const.USER_STATUS.REGISTER')) //REGISTER=1
            {
                logger("status". $user->status );
                return view('auth.main.register')->with('message', 'すでに本登録されています。ログインして利用してください。');
            }
            // ユーザーステータス更新
            $user->status = config('const.USER_STATUS.MAIL_AUTHED');
            $user->verify_at = Carbon::now();
            if($user->save()) {
                return view('auth.main.register', compact('email_token'));
            } else{
                return view('auth.main.register')->with('message', 'メール認証に失敗しました。再度、メールからリンクをクリックしてください。');
            }
        }
    }
```

以下のときをエラーをとしています。

1. 登録済みのトークンのとき
2. メール認証済みのユーザーのとき
3. 本登録済みのユーザーのとき

エラーのときは、Viewにメッセージを通知するようにしています。

#### statusカラム追加
メール認証済みかどうかは、`email_verify`カラムで扱うようにしていますが、「本登録済み」かなどのステータスも扱いたいと思います。
`status`カラムを`User`テーブルに追加しましょう。
（`email_verify`と内容が被るかもしれませんが、ここでは別々に扱うようにしています。）

migrationファイルを作成します。

```
$ php artisan make:migration add_column_users_table --table=users
```

```php
class AddColumnUsersTable extends Migration
{
    public function up()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->tinyInteger('status')->default(0);
        });
    }

    public function down()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->dropColumn('status');
        });
    }
}

```

`migrate`しましょう。


#### config: constの追加
`showForm()`で`config('const.USER_STATUS.REGISTER')`の記述がありますが、これはステータス値をconst（定数）で管理するようにしています。
`config/const.php`を作成し、以下のように設定してください。

```php:config/const.php
<?php

return [
    /*
    |--------------------------------------------------------------------------
    | Const
    |--------------------------------------------------------------------------
    */

    // 0:仮登録 1:本登録 2:メール認証済 9:退会済
    'USER_STATUS' => ['PRE_REGISTER' => '0', 'REGISTER' => '1', 'MAIL_AUTHED' => '2', 'DEACTIVE' => '9',],
];
```
こうすることで、`config('const.XXX')`で設定値を参照することができます。
配列のときは`config('const.array.XXX')`のように書きます。

#### viewの追加
次に、Viewを追加しましょう。
`showFomr()`で`return view('auth.main.register')`と書きましたね。このviewを作成します。

```php:auth/main/register.blade.php


@extends('layouts.app')
@section('content')
    <div class="container">
        <div class="row justify-content-center">
            <div class="col-md-8">
                <div class="card">
                    <div class="card-header">本会員登録</div>

                    @isset($message)
                        <div class="card-body">
                            {{$message}}
                        </div>
                    @endisset

                    @empty($message)
                        <div class="card-body">
                            <form method="POST" action="{{ route('register.pre_check') }}">
                                @csrf
                                <div class="form-group row">
                                    <label for="name" class="col-md-4 col-form-label text-md-right">名前</label>
                                    <div class="col-md-6">
                                        <input
                                            id="name" type="text"
                                            class="form-control{{ $errors->has('name') ? ' is-invalid' : '' }}"
                                            name="name" value="{{ old('name') }}" required>

                                        @if ($errors->has('name'))
                                            <span class="invalid-feedback">
                                            <strong>{{ $errors->first('name') }}</strong>
                                            </span>
                                        @endif
                                    </div>
                                </div>

                                <div class="form-group row">
                                    <label for="name_pronunciation"
                                           class="col-md-4 col-form-label text-md-right">フリガナ</label>

                                    <div class="col-md-6">
                                        <input id="name_pronunciation" type="text"
                                               class="form-control{{ $errors->has('name_pronunciation') ? ' is-invalid' : '' }}"
                                               name="name_pronunciation" value="{{ old('name_pronunciation') }}"
                                               required>

                                        @if ($errors->has('name_pronunciation'))
                                            <span class="invalid-feedback">
                                            <strong>{{ $errors->first('name_pronunciation') }}</strong>
                                            </span>
                                        @endif
                                    </div>
                                </div>

                                <div class="form-group row">
                                    <label for="name_pronunciation"
                                           class="col-md-4 col-form-label text-md-right">生年月日</label>
                                    <div class="col-md-6">
                                        <div class="row">
                                            <div class="col-md-4">
                                                <select id="birth_year" class="form-control" name="birth_year">
                                                    <option value="">----</option>
                                                    @for ($i = 1980; $i <= 2005; $i++)
                                                        <option value="{{ $i }}"
                                                                @if(old('birth_year') == $i) selected @endif>{{ $i }}</option>
                                                    @endfor
                                                </select>
                                                @if ($errors->has('birth_year'))
                                                    <span class="help-block">
                                                        <strong>{{ $errors->first('birth_year') }}</strong>
                                                    </span>
                                                @endif
                                            </div>年

                                            <div class="col-md-3">
                                                <select id="birth_month" class="form-control" name="birth_month">
                                                    <option value="">--</option>
                                                    @for ($i = 1; $i <= 12; $i++)
                                                        <option value="{{ $i }}"
                                                            @if(old('birth_month') == $i) selected @endif>{{ $i }}</option>
                                                    @endfor
                                                </select>
                                                @if ($errors->has('birth_month'))
                                                    <span class="help-block">
                                                        <strong>{{ $errors->first('birth_month') }}</strong>
                                                    </span>
                                                @endif
                                            </div>月

                                            <div class="col-md-3">
                                                <select id="birth_day" class="form-control" name="birth_day">
                                                    <option value="">--</option>
                                                    @for ($i = 1; $i <= 31; $i++)
                                                        <option value="{{ $i }}"
                                                            @if(old('birth_day') == $i) selected @endif>{{ $i }}</option>
                                                    @endfor
                                                </select>

                                                @if ($errors->has('birth_day'))
                                                    <span class="help-block">
                                                        <strong>{{ $errors->first('birth_day') }}</strong>
                                                    </span>
                                                @endif
                                            </div>日
                                        </div>

                                        <div class="row col-md-6 col-md-offset-4">
                                            @if ($errors->has('birth'))
                                                <span class="help-block">
                                                    <strong>{{ $errors->first('birth') }}</strong>
                                                </span>
                                            @endif
                                        </div>
                                    </div>
                        </div>

                        <div class="form-group row mb-0">
                            <div class="col-md-6 offset-md-4">
                                <button type="submit" class="btn btn-primary">
                                    確認画面へ
                                </button>
                            </div>
                        </div>
                        </form>
                </div>
                @endempty
            </div>
        </div>
    </div>
    </div>
@endsection
```

Viewでは、

- Controllerからエラーメッセージ(`$message`)があるとき
  - エラーメッセージのみを表示する
- Controllerからエラーメッセージがないとき
  - 本会員の入力フォームを表示する

としています。

#### 本会員カラムの追加
さて、viewで入力してもらうカラムを追加しましょう。

```sh
php artisan make:migration add_columns_users_table --table=user
```
今回はUsersモデルに追加していきます。

+ 名前
+ フリガナ
+ 生年月日

「名前」はデフォルトでカラムがありますので、それ以外を追加してみましょう。

```php:migration
    public function up()
    {
        Schema::table('users', function (Blueprint $table) {
          $table->string('name_pronunciation')->nullable();
          $table->integer('birth_year')->nullable();
          $table->integer('birth_month')->nullable();
          $table->integer('birth_day')->nullable();
        });
    }

    public function down()
    {
        Schema::table('users', function (Blueprint $table) {
          $table->dropColumn('name_pronunciation');
          $table->dropColumn('birth_year');
          $table->dropColumn('birth_month');
          $table->dropColumn('birth_day');
        });
    }
```
`php artisan migrate`を実行します。


### 確認画面の追加
#### Controllerに`mainCheck()`を追加

確認画面のviewを返すメソッドを用意します。
`RegisterController`に追加します。

```php:RegisterController.php
  public function mainCheck(Request $request)
  {
    $request->validate([
      'name' => 'required|string',
      'name_pronunciation' => 'required|string',
      'birth_year' => 'required|numeric',
      'birth_month' => 'required|numeric',
      'birth_day' => 'required|numeric',
    ]);
    //データ保持用
    $email_token = $request->email_token;

    $user = new User();
    $user->name = $request->name;
    $user->name_pronunciation = $request->name_pronunciation;
    $user->birth_year = $request->birth_year;
    $user->birth_month = $request->birth_month;
    $user->birth_day = $request->birth_day;

    return view('auth.main.register_check', compact('user','email_token'));
  }
```
確認画面では入力内容を表示します。
入力内容でUsersモデルを更新したいので、viewにデータを渡し、次のControllerに渡します。

#### Viewの作成
`register_check.blade.php`を作成します。

```php:register_check.blade.php

@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row justify-content-center">
        <div class="col-md-8">
            <div class="card">
                <div class="card-header">本会員登録確認</div>

                <div class="card-body">
                    <form method="POST" action="{{ route('register.main.registered') }}">
                        @csrf

                        <div class="form-group row">
                            <label for="name" class="col-md-4 col-form-label text-md-right">名前</label>
                            <div class="col-md-6">
                                <span class="">{{$user->name}}</span>
                                <input type="hidden" name="email" value="{{$user->name}}">
                            </div>
                        </div>

                        <div class="form-group row">
                            <label for="name_pronunciation" class="col-md-4 col-form-label text-md-right">フリガナ</label>
                            <div class="col-md-6">
                                <span class="">{{$user->name_pronunciation}}</span>
                                <input type="hidden" name="name_pronunciation" value="{{$user->name_pronunciation}}">
                            </div>
                        </div>

                        <div class="form-group row">
                            <label for="birth" class="col-md-4 col-form-label text-md-right">生年月日</label>
                            <div class="col-md-6">
                                <span class="">{{$user->birth_year}}年</span>
                                <input type="hidden" name="birth_year" value="{{$user->birth_year}}">
                                <span class="">{{$user->birth_month}}月</span>
                                <input type="hidden" name="birth_month" value="{{$user->birth_month}}">
                                <span class="">{{$user->birth_day}}日</span>
                                <input type="hidden" name="birth_day" value="{{$user->birth_day}}">
                            </div>
                        </div>


                        <div class="form-group row mb-0">
                            <div class="col-md-6 offset-md-4">
                                <button type="submit" class="btn btn-primary">
                                    本登録
                                </button>
                            </div>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
@endsection

```

#### ルーティングの追加
ルーティングはこんな感じです。

```
Route::post('register/main_check', 'Auth\RegisterController@mainCheck')->name('register.main.check');
```

### 本登録の実装
ようやく最後の処理です。

確認画面で本登録ボタンを押したら本会員登録されるようにしましょう。

#### ルーティングの追加

```
Route::post('register/main_register', 'Auth\RegisterController@mainRegister')->name('register.main.registered');
```

#### Controllerに`mainRegister()`を追加
```php:RegisterController.php
  public function mainRegister(Request $request)
  {
    $user = User::where('email_verify_token',$request->email_token)->first();
    $user->status = config('const.USER_STATUS.REGISTER');
    $user->name = $request->name;
    $user->name_pronunciation = $request->name_pronunciation;
    $user->birth_year = $request->birth_year;
    $user->birth_month = $request->birth_month;
    $user->birth_day = $request->birth_day;
    $user->save();

    return view('auth.main.registered');
  }
```


### viewの追加
`auth/main/registered.blade.php`を追加。

```php:auth/main/registered.blade.php
@extends('layouts.app')

@section('content')
    <div class="container">
        <div class="row justify-content-center">
            <div class="col-md-8">
                <div class="card">
                    <div class="card-header">本会員登録完了</div>

                    <div class="card-body">
                        <p>本会員登録が完了しました。</p>
                        <a href="{{url('/')}}" class="sg-btn">トップページへ戻る</a>

                    </div>
                </div>
            </div>
        </div>
    </div>
@endsection
```

## 完成
お疲れ様です。Laravel5.6でのメール認証は以上です。
あなたのサイトに合わせて内容を変更してみてください！
ソースコードは、[こちら](https://github.com/nitaking/email-verify)から参照ください！


## 参考

以下のサイトを参考にしています。半分くらいこちらの翻訳記事と言ってもいいかもしれません。

1. [How to Use Queue in Laravel 5\.4 For Email Verification](https://hackernoon.com/how-to-use-queue-in-laravel-5-4-for-email-verification-3617527a7dbf)
上記サイトではQueueを使用していますが、今回は使用していません。