【Laravel】Localhostでgmailを使ってメールを送信する方法。Mailableを使わない方法と使う方法。

Laravelで**Gmailを使って問い合わせがあった場合に自動でメールを送信する機能**を作成する。

いろんなサイトで送信方法に関するページがあるが、ControllerとMailableの違いなど、どのファイルがなんの処理をしているのかがわかりにくかったので一つづつ確認しながら作成し理解を深める。


##目次

1. [概要](#概要)
    2. [MailファサードとMailableクラスの違い](#mailファサードとmailableクラスの違い)
3. [メール送信に必要なファイル](#メール送信に必要なファイル)
4. [.envの設定](#envの設定)
    5. [Gmailのパスワード](#gmailのパスワード)
    6. [ポート番号587と465の違い](#ポート番号587と465の違い)
    7. [（補足）`MAIL_MAILER=log`の機能](#補足mail_mailerlogの機能)
    8. [`MAIL_FROM_ADDRESS`とは？`MAIL_USERNAME`との違い](#mail_from_addressとはmail_usernameとの違い)
    9. [`MAIL_FROM_NAME`とは？](#mail_from_nameとは)
10. [コントローラの作成](#1-コントローラの作成)
    11. [use Mailとは？](#use-mailとは)
    12. [indexアクションの中身](#indexアクションの中身)
    13. [sendアクションの中身](#sendアクションの中身)
    14. [sendメソッド](#sendメソッド)
    15. [Mailファサードのメソッド一覧](#mailファサードのメソッド一覧)
    16. [入力データを渡す方法](#入力データを渡す方法)
17. [ルーティングの作成](#2-ルーティングの作成)
18. [コンタクトフォームの作成（view）](#3-コンタクトフォームの作成view)
19. [メール内容の作成（view）](#4-メール内容の作成view)
20. [サーバーを起動とメール送信処理の実行](#5-サーバーを起動とメール送信処理の実行)
21. [Mailableを使ったメール送信](#mailableを使ったメール送信)



<br>
##概要
Laravelメールを送信する機能に、`Mailファサード`と`Mailable`クラスがある。

どちらもメール本文となるviewを指定できたりと類似機能があるので混乱のタネになる。

**コントローラのsendアクションとMailファサードのsendメソッドも異なる**ので注意が必要。


<br>
###MailファサードとMailableクラスの違い
**Mailファサード（を使ったコントローラ）は必須**だけど、**Mailableはなくてもメール送信可能**。

Mailableは本文と添付ファイルの組み合わせを複数パターン作るときに便利。


**▼`Mailファサード`**

- コントローラに記述。メール送信に必須。
- `use Mail;`で読み込む
- 使い方は`Mail::メソッド` 


<br>
**▼`Mailableクラス`**

- Mailファサードのサポート役
- メール本文を指定できる。
- **なくてもメールは送信できる**。
- 添付ファイルの指定が簡単。
- `php artisan make:mail [mailableクラス名]`で生成


Mailableを使うパターンと使わないパターンのそれぞれでメールの送信方法を確認する。


<br>
###メール送信に必要なファイル

| ファイル | 必須 | 内容 |
|:-:|:-:|:--|
| .env  | ✔︎ | 送信元となるgmailを使うための、環境変数を記述する。メアドとPWなど  |
| web.php  | ✔︎  | ルーティングの設定。コンタクトフォームのルートや送信後のPOSTメソッドで実行するアクションの指定など  |
| controller  | ✔︎  | Mailファサードで送信先やメッセージの内容を指定する  |
| コンタクトフォームのview  | ✔︎ | submitボタンクリックでメール送信を発火する  |
| メール本文のview  | ✔︎  | 送信するメールの本文  |
| mailableのクラス  |   | メール送信先やメッセージの内容を指定する  |



<br>
##.envの設定
Gmailを送信元のメールサーバーとして使うため、環境変数の設定が必須。

ルートディレクトリ直下の.envの下記部分に追記する。

```:デフォルト
MAIL_MAILER=smtp
MAIL_HOST=mailhog
MAIL_PORT=1025
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS=null
MAIL_FROM_NAME="${APP_NAME}"
```

　　　↓

```:変更後
MAIL_MAILER=smtp  
MAIL_HOST=smtp.gmail.com     //gmailを指定
MAIL_PORT=587                //メッセージ送信のポート（465ではない）
MAIL_USERNAME=xxxx@gmail.com   //gmailアドレス
MAIL_PASSWORD=xxxxxxxxxxxxxxxx  //16桁のPW
MAIL_ENCRYPTION=tls          //tls通信
#MAIL_FROM_ADDRESS=null      //gmailの場合不要
MAIL_FROM_NAME="送信者の名前"    //メールの送信者に表示される名前
```


###Gmailのパスワード
スマホやPCではなくLaravelなどの外部アプリからGmailを使う場合は**アプリパスワード**を作成する必要がある。

Googleアカウントにログイン

  ↓

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563526/f828bac2-2164-f9a7-eb9a-969392397c9e.png)|
|:--|

  ↓ セキュリティ

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563526/3878785b-1e36-d77c-bdbd-b7afb43b5ef0.png)|
|:--|

  ↓ アプリパスワード

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563526/05f29a51-edf7-0616-2830-677d7744506f.png)|
|:--|

  ↓ アプリを選択：メール
  ↓ デバイスを選択：その他（名前を入力） （例：Laravelなどなんでもいい）

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563526/aaef1701-2c7b-aba4-cdc4-41802b49e4f4.png)|
|:--|

  ↓ アプリを選択：生成

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563526/6fe810df-9442-2d27-f0c7-06320323c11c.png)|
|:--|

表示された**16桁のパスワードをコピー**。（一度しか表示されない！）

これで、アプリパスワードの生成が完了。



<br>
###ポート番号587と465の違い
`MAIL_PORT=587`はサイトによっては465を使っているところもある。

どちらもメール送信用のポートだが587推奨。

メール送信のプロトコルで指定したSMTP専用のポートが587。
465は過去に使われていた名残で今も使えるが587が正式とのこと。（465はTLS用のポート）


<br>
###（補足）`MAIL_MAILER=log`の機能
Gmailを使うためのMAIL_MAILERにはSMTPを指定している。これをlogに変更すると、メールを送信せずに、メールの内容をログに吐き出すようになる。

Gmailなどを使わずに簡易的にメール機能を確認したい場合に使える。

**▼ファイルの出力先**
storage > logs > laravel.log

**▼出力例**

```:laravel.log
メッセージを送信しました。  
[2021-01-19 02:11:01] local.DEBUG: Message-ID: <c00e537b1a501@127.0.0.1>
Date: Tue, 19 Jan 2021 02:11:01 +0000
Subject: =?utf-8?Q?=E3=83=86=E3=82=B9=E3=83=88=E9=80=81=E4=BF=A1?=
From: xxx@gmail.com
To: xxx@gmail.com
MIME-Version: 1.0
Content-Type: text/html; charset=utf-8
Content-Transfer-Encoding: quoted-printable
```


<br>
###MAIL_FROM_ADDRESSとは？MAIL_USERNAMEとの違い
`MAIL_FROM_ADDRESS`と`MAIL_USERNAME`に同じメールアドレスを記載している例があるが、**gmailの場合`MAIL_FROM_ADDRESS`は不要**。

`MAIL_FROM_ADDRESS`はメールに表示されるメール送信元の表示を変更する機能。

gmailの場合は、`MAIL_USERNAME`が送信元のメアドになるため、`MAIL_FROM_ADDRESS`を記述しても**gmailによって書き換えられてしまう**。


<br>
###`MAIL_FROM_NAME`とは
MAIL_FROM_NAMEに指定した値が、実際にメール送信された時のメール送信者のところに表示される。

例えば、`MAIL_FROM_NAME="sample sender"`の場合、以下のように表示される

**sample sender &lt;xxx@gmail.com&gt;**

指定がない場合は、Exampleとなる。




<br>
<br>
##定型のメッセージを返信する機能の作成
まずは、入力内容などを使わず、単に決められたメッセージを返す簡単な機能を作成することで、メール送信ができることを確認する。

<br>
##1. コントローラの作成
コンタクトフォームの表示とメール送信を行うコントローラを作成する。

作成するのは１ファイルのみでOK。

・`$ php artisan make:controller [コントローラ名]`

「app > Http > Controllers > コントローラ名.php」 が生成される。

<br>
**▼実例**

```
$ php artisan make:controller ContactController
Controller created successfully.
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563526/75dc733f-b59b-9b65-e1ea-f5c5825b4624.png)


ファイルを開いて以下を追記する。追記するのは３点。

1. Mailファサードのuse宣言
2. indexアクション（コンタクトフォームの表示）
3. sendアクション（メール送信処理）

```php:ContactController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Mail;  //追記

class ContactController extends Controller
//以下追記
{
    public function index()   //コンタクトフォームを表示
    {
        return view('contact.index');
    }

    public function send(Request $request)  //メールの自動送信設定
    {
        Mail::send('emails.text', [], function($data){
                $data   ->to('送信先のメアド')
                        ->subject('送信メールの表題');
        });

        return back()->withInput($request->only(['name']))
                     ->with('sent', '送信完了しました。');  //送信完了を表示
    }
}
```


<br>
###use Mailとは？
`use Mail`はMailファサードのuse宣言。

`Illuminate\Support\Facades\Mail::class`のaliasなので、`use Illuminate\Support\Facades\Mail`としても同じ。


**▼aliasの確認**
app > config > app.php　にデフォルトで記載されている。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563526/791a1e74-a556-e219-1972-335cd1be4e3b.png)

```php:app.php
'Mail' => Illuminate\Support\Facades\Mail::class,
```


<br>
###indexアクションの中身

`return view('contact.index');`

ルートで**ContactControllerのindexアクション**が指定された場合に、ビューとして、ファイルパス **views > contact > index.blade.php** を返す。

ルーティングとビューは後ほど作成する。


<br>
###sendアクションの中身
メール送信機能を担う重要なアクション。


```php:
    public function send(Request $request)  //メールの自動送信設定
    {
        Mail::send('emails.text', [], function($data){
                $data   ->to('送信先のメアド')
                        ->subject('送信メールの表題');
        });

        return back()->withInput($request->only(['name']))
                     ->with('sent', '送信完了しました。');  //送信完了を表示
    }
}
```

####▼`public function send(Request $request)`
sendはアクション名。引数では、Requestクラスのインスタンスを変数$requestとして渡している。

この手法をメソッドインジェクション（依存注入）と呼ぶ。

[依存注入とは？](https://qiita.com/yuta-38/items/92f008143aadbe8cbd3e)


####▼`Mail::send`
Mailファサードのsendメソッドを呼び出している。


####▼sendメソッド
`send('ビュー', 関数に渡すデータ, 関数)`

- **３つの引数はすべて必要**でどれかが抜けるとエラーになる。
- 返信用メールにデータ（例えば、宛先や名前など）を渡す場合は、第２引数に記述する。
- 第３引数の関数で宛先やメールタイトルを指定する。


<br>
**▽データがない場合の記述例**

```php:
Mail::send('emails.text', [], function($data){
  //処理
});
```


<br>
**▽データがある場合の記述例**

```php:例１
Mail::send('emails.text', ['msg'=>'ありがとう！'], function($message){
  //処理
});
```


```php:例２
$data = $request->all()   //送信されてきたすべてのデータ
Mail::send('emails.text', $data, function($message){
  //処理
});
```


<br>
**※sendメソッドの引数が一つの場合**
Mailableクラスを使用する場合はsendメソッドでMailableクラスのインスタンスを渡す。その場合引数は１つとなる。

・例：`send(new [Mailableクラス名]($data)`

この場合、ファイル上方でMailableクラス名のuse宣言がなされている必要がある。



<br>
####▼Mailファサードのメソッド一覧
    
- `to('メアド', '表示名')`：宛先のメアド。表示名はなくてもいい。
- `subject('テキスト')`：メールの標題
- `cc('メアド')`: cc送信先のメアド
- `bcc('メアド')`: bcc送信先のメアド
- `from('メアド', '表示名')`: 

<br>
**・toメソッドの表示名**
送信したメールのtoの部分のメールアドレスを、指定した表示名に置き換える。


<br>
**・fromメソッドの注意点**
fromメソッドのメアドは環境変数の`MAIL_FROM_ADDRESS`を上書きする処理のためgmailの場合意味をなさない。

表示名で`MAIL_FROM_NAME`を上書きすることができる。ただしこの場合でも第一引数にダミーでなんらかのメアドを入れておかないとエラーになる。



<br>
##returnの処理
returnは**送信処理完了後に表示するページや内容**を指定する。

returnの記載がない場合、**sendアクションが実行されると空白ページが表示**される。


・`return redirect('パス');`
redirect関数でパスを指定すると、指定したパスに飛ぶ。

・`return back();`
元のページを表示する。


<br>
###入力データを渡す方法
ページ遷移をした後に、そのページにフォームの入力データを渡したい場合に使えるメソッドがある。

・`withInput()` 
入力内容をすべて渡す。データの取得は`old('キー名')`

・`withInput($request->only(['name']));`
特定のデータのみ渡す。


・`with('キー名', 'データ')`
指定したデータを渡す。「送信完了しました」などを渡せる。受け取りは`session('キー名')`。
if文の条件で存在確認をしたい場合は`Session::has('キー名')`

**▼実例**

```php:
 return back()->withInput($request->only(['name']))
              ->with('sent', '送信完了しました。');
```

よってこれは、現在のページに（１）キー名がnameのデータと、（２）キー名sentで「送信完了しました。」という２つの情報を渡している。

実際に画面に表示する処理はこの後のビュー作成時に指定する。


<br>
##2. ルーティングの作成
ルーティングに作成したコントローラのアクションを登録する。

routes > web.php　に以下を追記。

```php:web.php
Route::get('contact', 'ContactController@index');
Route::post('contact', 'ContactController@send');
```

・1行目
URL　/contactにアクセスしたときに、ContactControllerのindexアクションを実行する。

・2行目
/contactページでpostメソッドが使われたとき、ContactControllerのsendアクションを実行する。


<br>
####（注意点）Laravel8の場合
Laravel8の場合、デフォルトではコントローラの名前空間を完全なパスで表記しなければいけない。

省略表記するためには、app > Providers > RouteServiceProvider.phpのコメントアウトを解除する。（以下ページ参照）

＞[コメントアウトの解除場所](https://qiita.com/drafts#routeserviceproviderphp%E3%81%AE%E3%82%B3%E3%83%A1%E3%83%B3%E3%83%88%E3%82%A2%E3%82%A6%E3%83%88%E3%82%92%E8%A7%A3%E9%99%A4%E3%81%99%E3%82%8B)




<br>
##3. コンタクトフォームの作成（view）
/contactにアクセスしたときに表示するビューを作成する。

indexアクションで`view('contact.index')`を指定しているので、**resources > views > contact > index.blade.php** を作成する。

views配下ならどこでもいいが、contactディレクトリを作成するのはコンタクトフォームに様々な種類ができたときにまとめて保存しておくため。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563526/8c1d5a5a-a8c0-8839-5546-e496d9b99d5a.png)


```php:index.blade.php
@if ( Session::has('sent'))
<div>
    <p>{{old('name')}}さん、{{ session('sent') }}</p>
</div>
@endif

<form action="{{ url('contact') }}" method="POST">
    @csrf
 
    <p>名前：<input type="text" name="name"></p>
 
    <input type="submit" value="送信">
</form>
```

・`@if ( Session::has('sent'))`
withメソッドで渡されたデータ(キー名:sent)が存在するなら以下のdivタグを表示する。

つまり、送信ボタンが押された場合にこのdivタグが表示される。

```php:Controllerのsentアクション
 return back()->withInput($request->only(['name']))
              ->with('sent', '送信完了しました。');
```

・old('name')
`withInput()`で渡されたデータ

・session('sent')
`with()`で渡されたデータ





<br>
##4. メール内容の作成（view）
送信されるメール本文となるビューを作成する。
コントローラのsendアクションでビューを`emails.text`と指定しているので、以下パスにファイルを作成する。

resources > views > emails > text.blade.php

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563526/b73e2921-76f8-78b9-1df1-d09629ed580a.png)


```php:text.blade.php
emailsディレクトリのtext.blade.phpの内容です。
```


<br>
##5. サーバーを起動とメール送信処理の実行

```
$ php artisan serve

http://127.0.0.1:8000/
```

http://127.0.0.1:8000/contact にアクセスする。

 ↓ contacts.index.blade.phpの内容が表示される

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563526/1469083f-f3be-5466-3a8f-4d4b03540266.png)|
|:--|

　↓ 「送信」をクリック

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563526/04966da8-e39b-3977-80fd-8a3e9bb81e79.png)|
|:--|

<br>
**▼Gmailの受信内容**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563526/fc11c5e1-f404-8721-ca8c-a32ba1a90c5b.png)

ページも表示され、Gmailにもメッセージが届いている。


<br>
##Mailableを使ったメール送信
ここまででかなり長くなったので、Mailableを使ったメール送信は別記事で作成します。。