【Laravel】AWSのSESメールサーバでユーザー登録時に確認メールを送信するまでの流れ(queueで非同期送信)

プログラミング初心者の勉強ブログ #131

Amazon SESをLaravelで利用していく。ユーザー登録から、そのユーザーのメールアドレス宛に確認メールを送るまでの流れをまとめる。queueによる非同期送信を噛ませての実装。RailsのActive Jobやってたときを思い出す。

 

目次

[toc]

 

実装の流れ

大まかに2つに分けると、

  1. Amazon SESの設定(メールアドレス登録、SMTP credentialsなるものの設定など)
  2. Laravel側の設定(.envの内容、Mailテンプレ作成、queueテーブル追加、Job作成など)

SES側を設定したのち、Laravel側でユーザー登録時にメールが送信されるよう、何やかんやしていく。

 

※AWSアカウントを既に持っている前提で且つ、Laravelのアプリ作成の基本事項は省略した内容でまとめていく。

※バージョンはLaravel 5.5。

 

 

Amazon SESの設定

とりあえずマネジメントコンソールで「ses」と検索。

コンソール画面

 

「Simple Email Service」をクリック。

 

メールアドレスの登録

あらかじめメールアドレスを登録しておかなければならない。「to」も「from」も、ここで登録したメールアドレスでないと、うまく起動しないので注意が必要。

 

左のメニューから「Email Address」を選択(上の方)。

SES画面

 

 

「Verify a New Email Adress」という青いボタンをクリック。

メールアドレス設定

 

登録する自分のメールアドレスを入力。

メールアドレス入力画面

 

すると入力したメールアドレス宛にメールが届く。リンクをクリックして認証完了。先ほどのSESの画面を見ると、「Verify」の文字が表示されているはず。

 

SMTP credentialsの設定

次はSMTP credentialsを設定していく。

左のメニュー真ん中ちょい下「SMTP Settings」を選択すると、以下の画面になる。

SES credentialの画面

青色の「Create My SMTP Credentials」をクリックする。

 

作成画面

味気ない画面が出たら、右下の「作成」を選択。

 

選択画面

これで認証用のUSER_NAMEとPASSWORDが作成される。「ユーザーのSMTPセキュリティ認証情報を表示」を押すことで確認できる。右下の「認証情報のダウンロード」はどちらでも良い。

 

usernameとpassword

 

Laravel側の設定

Larvel側では、ユーザー登録時にその登録したユーザーのメールアドレス宛に確認メールを送信したい。このようなメールの送信はqueueを用いて行うことが一般的で、そうしておくことで、もし大量のメール送信を行う場合にも対応できる。

やることは、

  • メールテンプレートの作成
  • Jobの作成
  • queueテーブルの作成
  • queueワーカーの起動
  • .envの設定

大まかにこんな感じ。

 

メールテンプレートの作成

まずartisanコマンドでファイルを生成する必要がある。

 

以下をターミナルで実行

php artisan make:mail TestMail

 

「TestMail」のところは任意の名前で大丈夫。このコマンド実行によって、「app/Mail/TestMail.php」が作成されているので、中身を編集していく。

 

app/Mail/TestMail.php

<?php

namespace App\Mail;

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

use App\Models\User; // 追加

class Test extends Mailable
{
    use Queueable, SerializesModels;

    protected $user; // 追加
    /**
     * Create a new message instance.
     *
     * @return void
     */
    public function __construct(User $user) // 編集
    {
        $this->user = $user; //追加
    }

    /**
     * Build the message.
     *
     * @return $this
     */
    public function build()
    {
     // 以下追加
        $this->from('xxxxxxxxxx@gmail.com');

        return $this
            ->subject('登録ありがとうございます')
            ->view('mail') // mail.blade.php
            ->with(['user' => $this->user]);
    }
}

 

ここの、

public function build()
    {
     // 以下追加
        $this->from('xxxxxxxxxx@gmail.com');

        return $this
            ->subject('登録ありがとうございます')
            ->view('mail') // mail.blade.php
            ->with(['user' => $this->user]);
    }

fromに設定するemailは、先ほどAmazon SESで登録したメールアドレスを入れる。withでuserを投げているので、メールテンプレート内でuser変数が利用できる。

 

次に、「resources/views」下に「mail.blade.php」ファイルを作成する。これが実際に送るメールのテンプレートとなる。

 

resources/views/mail.blade.php

{{ $user->name }} さん
ご登録ありがとうございます。

 

先ほどユーザー名を表示させている。

 

 

Jobの作成と設定

Jobファイルにメール送信の処理を書き込む。流れとしては、ユーザー登録処理の最後に、指定したJobファイルを実行させ、Jobファイルが実行されると、queueテーブルにレコードがinsertされる。queueテーブルは、起動させたqueueワーカーが定期的にテーブルの中を巡回し、レコードがあったとき、そのJobの内容(今回の場合メールの送信処理)を裏側で非同期実行する。

とにかくJobファイルを作成する必要がある。

 

以下をターミナルで実行

php artisan make:job SendMail

 

app/jobs/SendMail.phpに作成されたファイルを編集する。

 

app/jobs/SendMail.php

<?php

namespace App\Jobs;

use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;

// 追加(UserとTestMailとMailをインポート)
use App\Mail\TestMail as TestMail;
use App\Models\User;
use Mail;

class SendMail implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    protected $user;

    /**
     * Create a new job instance.
     *
     * @return void
     */
    public function __construct(User $user)
    {
        $this->user = $user;
    }

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
        // ユーザー宛にメールを送信する処理
        Mail::to($this->user->email)->send(new TestMail($this->user));
    }
}

 

app/jobs/SendMail.phpは、実施したいJobの内容を書き込むファイル。今回Jobファイルにはメール送信プログラムが設定させる。TestMailは、先ほど編集した「app/Mail/TestMail.php」を参照している。

 

あとはこのJobファイルをユーザー登録処理の最後に実行させ、queueテーブルにレコードを追加させる必要がある。

 

app/http/Controllers/AuthController.php

<?php

namespace App\Http\Controllers;

use App\Models\User;
use Illuminate\Http\Request;

use App\Http\Requests\Auth\Register;

use Mail;
use App\Mail\Test as TestMail;
use App\Jobs\SendMail as SendMailJob;


class AuthController extends Controller
{
    // 省略
    
    public function register(Request $request)
    {
        $user = User::create([
            'name' => $request->input('name'),
            'email' => $request->input('email'),
            'password' => bcrypt($request->input('password')),
        ]);

        // Jobの登録
        SendMailJob::dispatch($user);
    }

   // 省略
}

 

※今回の実装は「jwt」を利用しているため、Authコントローラーを独自で作成している状態。デフォルトのlaravelログイン機能の場合は、「RegisterController.php」で「registered」ファンクションを用いてオーバーライドさせる必要がある。

 

// Jobの起動
SendMailJob::dispatch($user);

これを一行追加することでJobが登録される。

 

queueの設定と起動

先ほどまで書き込んだ内容によって、Jobは「queueテーブル」に保存される。つまり、データベースにqueueテーブルを作成する必要がある。

 

以下をターミナルで実行

php artisan queue:table

 

実行するとdatabase/migrations下に「create_job_table.php」マイグレーションファイルが生成されるので、

php artisan migrate

を行なってテーブルを追加する。

 

最後に

 

以下をターミナルで実行

php artisan queue:work

 

queueワーカーを起動させる。これによってqueueテーブルにJobレコードあれば、その中のJobが実行される。

 

.envの設定

Mail関係の部分を以下のように変更する。

.env

// 省略

MAIL_DRIVER=smtp
MAIL_HOST=email-smtp.us-west-2.amazonaws.com(SESで確認)
MAIL_PORT=25(SESで確認)
MAIL_USERNAME=SESで作成したusername
MAIL_PASSWORD=SESで作成したpassword
MAIL_ENCRYPTION=TLS

// 省略

 

「MAIL_HOST」と「MAIL_PORT」は

hostとport

先ほどのSESの「SMTP Settings」に書かれているものをコピペする。

「MAIL_USERNAME」と「MAIL_PASSWORD」は

usernameとpassword

ここからコピペして完了。

 

うまくいっていれば、ユーザー登録完了後にメールが送信されるはず。

 

まとめ

久しぶりにがっつりめの内容を書いた気がする。RailsのActive Jobと仕組みは同じ感じ。本来ならもう少し画像に赤い枠つけたりしてわかりやすくしたかったが、めんどくさくなってしまった。メールサーバーとか久しぶり過ぎて全て忘れてた。SESは機会があれば今後使っていこうかなと思う。sendgrid忘れたし。

以上ありがとうございました。

 

返信を残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA