Laravelメール送信機能の実装でmailtrapやGmailのSMTPサーバーを使ってみる

# 内容
Webアプリケーションを制作するに当たり、メール送信機能が必要であることが多々あるかと思います。
今回はLaravel5.8の環境下で、mailtrapを使用と、GmailのSMTPを使用したメール送信の2つのパターンで機能実装をしてみたので、その実装過程を纏めて投稿します。

# 環境
macOS Mojave 10.14.6
Laravel Framework 5.8.33

# 1. SMTPサーバー
- 仮想のSMTPテストサーバー**mailtrap**を使って簡易的に実装
    - 実際のメールアドレスを使用せず、mailtrapサイト上で内容等を確認できるため、送信機能のテストが簡易的に行える
    - 開発段階で適当に入力したメールアドレスが実際に存在しても送信されることはない
- GmailのSMTPサーバーを使用して実装
    - 実際にメールが送信される


# 2. mailtrapを使用する場合の設定
## 2.1 mailtrapのアカウント作成
メールアドレスで新規登録もしくは、既存のGmailやgithubアカウントも使用できる。
https://mailtrap.io/register/signup?ref=header
![スクリーンショット 2019-08-29 16.56.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449626/67c8232e-933c-3d79-e422-6560c20dd435.png)

## 2.2 SMTPの情報をLaravelの設定に反映させる
### 2.2.1 設定値の確認
sign in したら**demo inbox**を開く
![スクリーンショット 2019-08-29 17.02.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449626/c4b55983-366e-d5de-e6f9-4d566474fdce.png)

**Integration**より**Laravel**を選択
![スクリーンショット 2019-08-29 17.05.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449626/6e308cc6-bdd5-8a99-6ce8-7b2d373ee31a.png)

**SMTP settings**の情報を**env**もしくは**config/mail.php**のどちらかに設定(念のため両方)
![スクリーンショット 2019-08-29 17.06.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449626/ab7ac6c3-9639-cd12-d3cb-bd758716d730.png)

### 2.2.2 実際に設定する
上記で確認した**env**もしくは**config/mail.php**の値をそれぞれのファイルの該当部にコピペする

```php:.env
MAIL_DRIVER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=4b5fb1796bf652  // コピペの内容のままで良い
MAIL_PASSWORD=22c902aa6ac123  // コピペの内容のままで良い
MAIL_FROM_ADDRESS=hoge@gmail.com  // どのアドレスから送信するかを記載
MAIL_FROM_NAME=name  // 名前を適当に設定
```

上記内容を**confing/mail.php**でも同様に設定する

設定完了後は各種キャッシュクリア

```sh
$ php artisan cache:clear
$ php artisan config:cache
```

# 3. GmailのSMTPを使う場合の設定
GmailのSMTPを使用する場合はセキュリティの都合上、Gmailアカウントの設定変更が必要となる。

- 安全性の低いアプリ許可をオンにする方法
- 二段階認証を有効にし、アプリパスワードを発行する方法


## 3.1 安全性の低いアプリ許可をオンにする方法
- 安全性の低いアプリの許可をオンにする
    - https://myaccount.google.com/lesssecureapps
    - こちらは、二段階認証を有効にしている場合はオンにできない仕様である。すでに2段階認証が有効にされている場合は設定を解除しても良いが、下記、二段階認証有効下でアプリパスワードを発行する方法をオススメする
- **.env**ファイルを下記の通り設定する

```php:.env
MAIL_DRIVER=smtp
MAIL_HOST=smtp.gmail.com
MAIL_PORT=587
MAIL_USERNAME=hoge@example.com  // メールアドレスを記載(下のFROMと同じで良い)
MAIL_PASSWORD=hogehogehoge  // Gmailアカウントの生のパスワード
MAIL_FROM_ADDRESS=hoge@example.com  // どのアドレスから送信するかを記載
MAIL_FROM_NAME=name  // 名前を適当に設定
```
上記内容を**confing/mail.php**でも同様に設定する


設定完了後は各種キャッシュクリア

```sh
$ php artisan cache:clear
$ php artisan config:cache
```

## 3.2 二段階認証を有効にし、アプリパスワードを発行する方法
- 二段階認証の有効化
    - https://myaccount.google.com/u/6/security?hl=ja 
    - ログインしたアカウントの**Googleアカウント**ページの**セキュリティ**より二段階認証プロセスを有効にする
- アプリパスワードの発行
    - 簡単に言うと**env**ファイルで設定する**MAIL_PASSWORD**に記載するパスワードを発行すること
    - ログインしたアカウントのGoogleアカウントページの**セキュリティ**よりアプリパスワードを設定する。
        - アプリを選択では「メール」を選択する
        - デバイスを選択では使用しているデバイスを選択する
    - 設定が終わると１６桁のアプリパスワードが発行されるため、それを**env**ファイルの**MAIL_PASSWORD**に記載
    - 注)デプロイするアプリケーションごとに発行する必要があり、使い回しだと認証が通らないので注意。(localで使用したものをデプロイ先で使えない)
   

![スクリーンショット 2019-08-29 18.38.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449626/98ab4b1c-04e0-75f5-5b3f-4bb4e4582a18.png)


**env**の設定値は、「安全性の低いアプリ許可をオンにする方法」の場合と比較し、**MAIL_PASSWORD**の内容が異なる

```php:.env
MAIL_DRIVER=smtp
MAIL_HOST=smtp.gmail.com
MAIL_PORT=587   // 587にする
MAIL_USERNAME=hoge@example.com  // メールアドレスを記載(下のFROMと同じで良い)
MAIL_PASSWORD=hogehogehoge  // 発行したアプリパスワードの設定
MAIL_FROM_ADDRESS=hoge@example.com  // どのアドレスから送信するかを記載
MAIL_FROM_NAME=name  // 名前を適当に設定
```

上記内容を**confing/mail.php**でも同様に設定する

設定完了後は各種キャッシュクリア

```sh
$ php artisan cache:clear
$ php artisan config:cache
```

# 4. Mailableクラス
設定値の入力が完了すれば、次は機能面の実装
Mailableクラスでは送信するメールの情報やその内容を設定できる

## 4.1 Mailableクラスの作成

次のコマンドを実行すると、**app/Mail/SamleMail.php**を生成される
今回はクラス名を**SampleMail**とする

```sh
$ php artisan make:mail {クラス名}
# 今回、作成するクラス名
$ php artisan make:mail SampleMail
```

- 生成された**app/Mail/SampleMail**の**build()**メソッドに送信するメールの送信元情報や、メールの内容を追記する
- メールの送信元や、メールの内容で状況に応じて変数を使用したい場合があるが、変数を使用する場合としない場合と2通り説明する

## 4.2 変数を使用せず、決まった送信元から決まった内容を送信する場合

```php:app/Mail/SamleMail.php
<?php

namespace App\Mail;

use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;

class SampleMail extends Mailable
{
    use Queueable, SerializesModels;

    /**
     * Create a new message instance.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * Build the message.
     *
     * @return $this
     */
    public function build()
    {
      return $this
          ->from('hoge@sample.com') // 送信元
          ->subject('テスト送信') // メールタイトル
          ->view('mail.send'); // メール本文のテンプレートとなるviewを設定
    }
}

```

## 4.3 変数を受け取る場合

今回、下記の例では次の変数*$content*をControllerから受け取ることとする
$content = ['name' => 'fuga', 'mail' => 'fuga@example.com'];
※Controller側の設定は次項で説明

```php:app/Mail/SamleMail.php
<?php

namespace App\Mail;

use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;

class SampleMail extends Mailable
{
    use Queueable, SerializesModels;

    /**
     * Create a new message instance.
     *
     * @return void
     */
    
    // 引数で受け取る変数
    protected $content;
    // コンストラクタ設定
    public function __construct($content)
    {
        // 引数で受け取ったデータを変数にセット
        $this->content = $content;
    }

    /**
     * Build the message.
     *
     * @return $this
     */
    public function build()
    {
      return $this
          ->from('hoge@exapmle.com') // 送信元
          ->subject('テスト送信') // メールタイトル
          ->view('mail.send') // メール本文のテンプレート
          ->with(['content' => $this->content]);  // withでセットしたデータをviewへ渡す
    }
}

```

# 5. Controllerの設定
Controller側では送信先とMailableクラスの振り分けを行う

```php:Controller
use App\Mail\OrderMail;
use Illuminate\Support\Facades\Mail;

public function store(Request $request){
  // フォームからのリクエストデータ全てを$contentに代入
  $content = $request->all();
  
// 特に変数を渡さない場合
Mail::to($content->email)->send(new SapmleMail);
// データの入った変数を渡す場合
Mail::to($content->email)->send(new SampleMail($content));
```

# 6. メール本文のテンプレート
Mailableクラスで設定したviewのメール本文のテンプレートの作成


```php:views/mail/send.blade.php
// withで変数を受け取った場合は変数を使用できる
{{ $contact->name }}　様
メール送信完了
```

# 7. メールの送信
以上で、メール送信機能が完成。
mailtrapではこのような感じでで表示されるようになる。

![スクリーンショット 2019-08-29 17.09.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449626/3e1b1c54-8e34-8e36-a825-41c3050918fe.png)