LaravelとAmazon SES を使ってメールを送ろう!


はじめに

タイトルの通り、とても簡単にLaravelとAmazon SESを使ってメールを送ることができます。
記事自体は長いのですが作業自体は特に難しくありません。
Laravel使ってメールを送りたいと考えている方(そうでない方も笑)、ぜひ記事に目を通していってください!

著者の環境

  • Laravel 8.78.1
  • PHP 8.0.8

本記事の概要

ゴール

アプリから以下のようなメールが送信できることを目標にしていきます。

項目 説明
from [email protected]
fromの表示名 アプリ名
to アプリにて指定した宛先

やること

メールを送信するために以下のステップを踏んでいきます。
もしご自身にとって不要なステップがあったら飛ばしてください。

IAMユーザーの作成

LaravelからSESにメールの送信リクエストをするには、認証のためにIAMユーザーが必要です。
(最終的に.envにIAMユーザーのアクセスキーやシークレットアクセスキーを記入します)

そのため、まずはIAMユーザーを作成しましょう。
今回は以下のようなポリシーを作成し、このポリシーを直接IAMユーザーにアタッチしました(直接IAMユーザーにポリシーアタッチするのは良くないのですが、テストなので許してください笑)

作成したポリシー
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "ses:SendEmail",
                "ses:SendRawEmail"
            ],
            "Resource": "*"
        }
    ]
}

【補足】 アクセスキーとシークレットアクセスキーを確認する方法

IAMユーザーのユーザーページから認証情報タブをクリックします。
アクセスキーの作成をクリックすると、アクセスキーとシークレットアクセスキーが確認できます。

SESの設定

SESを利用するには、送信するためのドメイン又はメールアドレスが必要になります。
今回は送信元にドメインを指定します。
以下独自ドメインの取得についても記載していますが、取得済みの方は読み飛ばしてください。

独自ドメインの取得

今回はfreeenomというサービスを用いて無料でドメインを取得しました。

  • freenomへの登録を済ませたらヘッダーにあるServices内のRegister New Domainをクリックします。

  • 好きなドメインのところでGet it nowを押します。そうすると、selectedに表示が切り替わります(今回はtest-ses.tkを選択しました)。

  • その後は完了画面になるまで、continue等を押していきます(完了画面は注文番号が出てくる画面です)

    ※ 途中にドメインを取得する期間を設定する場所があるので、その部分はご自身の希望の期間を設定してください。デフォルトは3ヶ月です。

これで独自ドメインの取得は以上になります。
しかしこのままではSESで色々ドメインの設定をした時に、freenomで管理をしなければならず結構面倒です。
そのためRoute53に管理を委任していきます。

  • まずはRoute53にて、先ほど取得した独自ドメインのホストゾーンを作成します。

  • そうしたら4つのNSレコードが作成されます(SOAレコードも作成されますが、今回はNSレコードのみ使用します)。

それではfreenomeにてRoute53のNSレコードを登録していきましょう。

  • freenomのヘッダーにあるServices内のMy Domainsをクリックします。

  • その後、自身のドメインのManage Domainというボタンを押下し、出てきた画面のNameserversをクリックします

  • 先ほどRoute53のNSレコードに記載してあったものを記入していきます。

  • 完了したらdigコマンドにてroute53のNSレコードが出てくるか確認しましょう。
    ※直ぐには反映されないこともあります。

$ dig NS test-ses.tk +short
ns-1347.awsdns-40.org.
ns-14.awsdns-01.com.
ns-1629.awsdns-11.co.uk.
ns-823.awsdns-38.net.

これで独自ドメインの設定は完了です。
それではSESの設定をしていきましょう。

SESの設定

  • SESのコンソール画面にいったらCreate identityというボタンを押します。

  • まずは、送信するドメインを設定します。

  • 次にDKIMの設定をしていきます。今回はSESにて簡単に設定できるEasyDKIMを選択しました。

  • Route53を見ると、設定したDKIMのCNAMEレコードが追記されています(画像の3つのレコード全てがDKIMのドメインです)。

【補足】DKIM(DomainKeys Identified Mail)について

メールの電子署名を用いた不正防止の仕組みです。送信者はメールに電子署名を行います。メール受信者がドメインが正式なものかを問い合わせて不正を防止しています。

サンドボックス外への移動

SESはデフォルトの状態で Amazon SES サンドボックスに配置されます。
これにより以下のような制限がかかってしまいます。

  • SESに登録したメールアドレス(ドメイン)からしかメールを送信することができない
  • 最大で 24 時間あたり 200 メッセージ
  • 最大で 1 秒あたり 1 メッセージを送信できます

どのアドレスへもメールを問題なく送信したい場合、Amazon SES サンドボックスから削除されるようにリクエストする必要があります。

  • SESのTopページからRequest production accessというボタンを押します

  • 各種必要な情報を入力して、Requestを送信します。

これでSESの設定は完了です。
次にLaravelの方の設定をしていきましょう。

Laravelの設定

各種準備

  • まずはライブラリをインストールします。
$ composer require aws/aws-sdk-php
  • 次に.envファイルを編集していきます。 使用するメーラーやIAMの情報を記入していきましょう。
.env
MAIL_MAILER=ses
MAIL_FROM_ADDRESS=[email protected] # @より前は好きな文字を記入し、@の後はSESにて設定したドメインを設定します。
MAIL_FROM_NAME="${APP_NAME}" #FROMの表示名をアプリ名以外にしたい場合は、書き換えてください。

# 作成したIAMユーザーのアクセスキーを記入する
AWS_ACCESS_KEY_ID=この部分はIAMのアクセスキーを記入してください。
AWS_SECRET_ACCESS_KEY=この部分はIAMのシークレットアクセスキーを記入してください
AWS_DEFAULT_REGION=ap-northeast-1 #東京リージョンではない場合は書き換えてください。
  • config/mail.phpの変更
    ※ 基本的に.envの設定値が適用されるので、第2引数は書き換えなくても動作しますが念の為設定しておきます。
config/mail.php
'default' => env('MAIL_MAILER', 'ses'),

'from' => [
    'address' => env('MAIL_FROM_ADDRESS', '[email protected]'),
    'name' => env('MAIL_FROM_NAME', 'Test'),
],
  • config/services.php
    ※ 基本的に.envの設定値が適用されるので、第2引数は書き換えなくても動作しますが念の為設定しておきます。
config/services.php
return [
    // 中略
    'ses' => [
        'key' => env('AWS_ACCESS_KEY_ID'),
        'secret' => env('AWS_SECRET_ACCESS_KEY'),
        'region' => env('AWS_DEFAULT_REGION', 'ap-northeast-1'),
    ],

];

実装

LaravelではMailファサードを使ってMailを送ることが出来ます。
Mailファサードのみでも送信することはできるのですが、メールの文面等はMailableクラスを用いると楽に実装できるので、今回はMailableクラスを用いようと思います。

  • Mailableの生成 bash $ php artisan make:mail TestMail 上記のartisanコマンドを打つと、app/Mail/TestMail.phpが作成されます。 メールの文面にDBのデータが必要な場合は、メンバー変数にModelを持ってきて、コンストラクタにModelをDIする必要があります。 今回はUserのデータを使用すると仮定します。
MailTest.php
<?php

namespace App\Mail;

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

use App\Models\User;

class MailTest extends Mailable
{
    use Queueable, SerializesModels;

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

    /**
     * Build the message.
     *
     * @return $this
     */
    // subjectメソッドでメールのタイトルを設定
    // viewメソッドでメールの本文が書いてあるbladeを指定
    public function build()
    {
        return $this
        ->subject('メールの題名')
        ->view('emails.test_content');
    }
}
  • メールの内容を実装

resources/views内にemails/test_content.blade.phpを作成します。

$ mkdir -p resources/views/emails && touch ./resources/views/emails/test_content.blade.php

メールの文面を書いていきます。
今回は『[ユーザー名]さんへのメール』という文面を記載しています。

test_content.blade.php
<body>
  <p>{{ $user->name }}さんへのメール</p>
</body>
  • メールの送信処理の実装
    Mailファサードを用いてtoメソッドにより送信先を設定し、sendメソッドによりMailableのインスタンスを引数にします。 この処理でメールを送ることが出来ます。
TestController.php
use App\Mail\MailTest;
use Illuminate\Support\Facades\Mail;

class TestController extends Controller
{
    public function index()
    {
        $mail_address = [自分が送りたい宛先];
        Mail::to($mail_address)->send(new MailTest($review,$user));
    }
}

これで以上となります!
最後まで読んでくださりありがとうございました。

参考記事