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タブへ。

Integrationsという箇所を見つけたら、ドロップダウンリストからLaravelを選択。その下に表示されるCredentialsのSMTPのUsernameとPasswordを控えます。
ローカル開発環境から設定します。.envファイルを開き、下記のように修正。(隠れファイルなのでご注意。隠しファイルを表示するにはMacならCommand + Shift + .同時押し)

.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です。方法は2つあって、コマンドラインを使う方法とHerokuサイト上でGUIで入力する方法です。HerokuサイトならSettingsタブを開いて、Config VarsでReveal Config Varを押すと入力欄が出てきます。

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

$ 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ファイルを編集するというやり方もありますが、機密情報がダダ漏れしてしまうのでやめた方が良さそうです。

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という形で作成しました。フォームの作成例です。必要最小限の表記にしています。

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規約では複数形でないといけないと書いてましたが、某教科書は単数形なので教科書に倣います。

$ php artisan make:controller ContactController

下記のように編集していきます。

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)

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

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

Mailableクラスの準備

Mailableとは、Laravelアプリが送信するメールを操作するクラスです。詳しくは公式ドキュメントを。今回はContactMail.phpという名前で作成しました。

php artisan make:mail ContactMail

app/MailディレクトリにContactMail.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)

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の受信箱でメールを受信することができます。

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