Laravel7フォームでお問い合わせが送信されたらサイト運営者にメールで知らせる

#やりたいこと
###要件
* コンタクトフォームから名前、メアド、メッセージを記入して送信すると、その内容がサイト運営者にメールが飛ぶ。
* アカウント登録がなくてもゲストでも送信できる。
* DBは使用しない。
* Heroku、ローカル開発環境（MAMP）両方で機能する。

初めてなので、まずはシンプルなものを実装。今後、入力確認画面とかエラーメッセージとか色々応用出来たらいいなと思っています。

###やるべきことを俯瞰します

* Mailtrapの準備
* Laravelアプリ内のメールの環境設定
* ビューの作成（xxx.blade.php）
* コントローラの設定（XxxController.php）
* ルートの設定（web.php）
* Mailableの準備（XxxXxx.php）
* メールのテンプレート作成（xxx.blade.php）

#やってみた

###Mailtrapの準備
Mailtrapとは、Webアプリで使用するメールを助けてくれるサービスです。
https://mailtrap.io/ でサインアップ（GitHub連携などで一瞬で登録出来ます）。

###Laravelアプリ内のメールの環境設定

Mailtrapを開いて、Inboxes→歯車マーク→SMTP Settingsタブへ。
![スクリーンショット 2020-09-22 14.04.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/645077/5394a9dd-d9f5-80d7-c0ae-466003e76cd6.png)
Integrationsという箇所を見つけたら、ドロップダウンリストからLaravelを選択。その下に表示されるCredentialsのSMTPのUsernameとPasswordを控えます。
ローカル開発環境から設定します。.envファイルを開き、下記のように修正。（隠れファイルなのでご注意。隠しファイルを表示するにはMacなら`Command + Shift + . `同時押し）


```terminal:.env
MAIL_MAILER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=Mailtrapを見てここ修正
MAIL_PASSWORD=Mailtrapを見てここ修正
MAIL_ENCRYPTION=Mailtrapを見てここ修正
MAIL_FROM_ADDRESS=お好みで修正
MAIL_FROM_NAME="${APP_NAME}" ここも適宜修正
```
次にHeroku用の環境。上記設定だけでは、Herokuでは機能しません。それもそのはず。私の場合、.envファイルを.gitignoreファイルに入れてgitの管理対象外にしているからです。
なので、Herokuの環境設定をすればOKです。方法は２つあって、コマンドラインを使う方法とHerokuサイト上でGUIで入力する方法です。HerokuサイトならSettingsタブを開いて、Config Varsで`Reveal Config Var`を押すと入力欄が出てきます。

コマンドラインなら下記のようなコマンドを。ちなみに私は、Laravelアプリのディレクトリにいる状態で行いました。.envファイルで行った設定をそのまんまHerokuにも設定してあげればよいですね。

```terminal
$ heroku config:set MAIL_HOST=smtp.mailtrap.io
$ heroku config:set MAIL_USERNAME=Mailtrapを見てここ修正
$ heroku config:set MAIL_PASSWORD=Mailtrapを見てここ修正
$ heroku config:set MAIL_ENCRYPTION=Mailtrapを見てここ修正
$ heroku config:set MAIL_FROM_ADDRESS=お好みで修正
```
余談で、下のようにconfig/mail.appファイルを編集するというやり方もありますが、機密情報がダダ漏れしてしまうのでやめた方が良さそうです。

```php:mail.app
   'mailers' => [
        'smtp' => [
            'transport' => 'smtp',
            'host' => env('MAIL_HOST', 'smtp.mailtrap.io'), //ここをMailtrapに変更
            'port' => env('MAIL_PORT', 587),
            'encryption' => env('MAIL_ENCRYPTION', 'tls'),
            'username' => 'Mailtrapを見てここ修正', //ここ修正
            'password' => 'Mailtrapを見てここ修正', //ここ修正
            'timeout' => null,
            'auth_mode' => null,
        ],
```

###ビューの作成（xxx.blade.php）
`resources/views/contact/contact.blade.php`という形で作成しました。フォームの作成例です。必要最小限の表記にしています。

```html:contact.blade.php
<form action="process" method="post">
  @csrf
  <div>
    <label for="name">お名前</label>
    <input type="text" name="name" id="name">
  </div>
  <div>
    <label for="email">メールアドレス</label>
    <input type="email" name="email" id="email">
  </div>
  <div>
    <label for="message">お問い合わせの内容</label>
    <textarea name="text" cols="40" rows="8" id="message"></textarea>
  </div>
  <div>
    <input type="submit" value="送信する">
  </div>
</form>
```
ポイント

* `@csfr`：Laravelで必須のCSRF対策。（Cross Site Request Forgeryの略）
* formタグのaction属性：フォーム送信後のアドレスになる
* formタグのmethod属性：post。HTTPのPOSTメソッドに相当。フォームのデータをサーバーに送信する。
* inputやtextareaタグのname属性：入力値の値はこのnameと一緒にサーバーに送信される重要な属性。

###コントローラの設定（XxxxController.php）
コマンドラインで、ファイルを作成します。あるサイトでは、Laravel規約では複数形でないといけないと書いてましたが、某教科書は単数形なので教科書に倣います。

```terminal
$ php artisan make:controller ContactController
```
下記のように編集していきます。

```php:ContactController.php
<?php
namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Mail;//追記
use App\Mail\ContactMail; //追記。後に作るMailable。後述。

class ContactController extends Controller
{
    //contact.blade.php表示
    public function index()
    {
        return view('contact.contact'); //'contactフォルダの中のcontace.blade.php'
    }
    //メール送信
    public function process(Request $request)
    {
        $request->validate([ //バリデーション
            'name'     => 'required',
            'email'    => 'required|email',
            'text'     => 'required',
        ]);
        $input = $request->all();
        unset($input['_token']); //CSRF非表示フィールド_token削除
        Mail::to('送信先メアド')->send(new ContactMail('contact.mail', 'お問い合わせを受信しました', $input));
        return redirect('/');
    }
}
```


###ルートの設定（web.php）

```php:web.php
//Contactページの表示
Route::get('contact', 'ContactController@index');

//フォームの受け取りとメール送信
Route::post('process', 'ContactController@process'); //先のformタグのaction属性はこの第一パラメータと関係する
```

###Mailableクラスの準備
Mailableとは、Laravelアプリが送信するメールを操作するクラスです。詳しくは[公式ドキュメント](https://readouble.com/laravel/7.x/ja/mail.html)を。今回はContactMail.phpという名前で作成しました。

```terminal
php artisan make:mail ContactMail
```
app/MailディレクトリにContactMail.phpが生成されました。

```php:ContactMail.php
<?php
namespace App\Mail;

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

class ContactMail extends Mailable
{
    use Queueable, SerializesModels;

    public $data; //追記
    /**
     * Create a new message instance.
     *
     * @return void
     */
    public function __construct($template, $subject, $data)
    {
        $this->subject = $subject; //件名
        $this->data = $data; //フォームで受信したデータ
    }

    /**
     * Build the message.送信するメールの設定はbuildメソッド
     * 
     * @return $this
     */
    public function build()
    {
        return $this->from('メールの発信先アドレス')//fromメソッドでメールの送信メアドを設定。
                    ->view('contact.mail');//メールのテンプレートを指定。ここではcontactフォルダのmail.blade.phpを指定。
    }
}
```
###メールのテンプレート作成（xxx.blade.php）


```html:views/contact/mail.blade.php
<head>
  <style>
    h1 {
      font-size: 18px;
    }
    p {
      font-size: 14px;
    }
  </style>
</head>
<body>
  <h1>{{$data["name"]}}様からの、お問い合わせを受信しました。</h1>
  
  <p>メールアドレス: {{$data["email"]}}</p>
  <p>内容:  {{$data["text"]}}</p>
</body>
```
ポイントは、Mailableクラスから受け取ったデータを`{{$data[""]}}`でフォームデータを表示できるという点でしょう。
#最後に
これでうまく設定できていれば、フォームで送信すると、Mailtrapの受信箱でメールを受信することができます。
![スクリーンショット 2020-09-22 20.59.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/645077/e2051c38-b821-e31e-449d-dc25b0e77901.png)


何かご指摘、アドバイスあればよろしくお願い申し上げます。