システムからメールを送るなら何を考える?Amazon SESを導入して分かった到達率・SMTP・DNS・送信制御のポイント
Webシステムを作っていると、次のようなメール送信機能が必要になることがあります。
- 仮登録メール
- パスワード再設定メール
- 予約確認メール
- 試験やイベントの案内
- 数百〜数千人への一括通知
実装だけを見ると、非常に単純な機能に見えます。
宛先
件名
本文
↓
SMTPで送信
しかし、企業向けシステムで実際に運用する場合、本当に考えるべきなのは、
メールを送れるかではなく、継続的に正しく届けられるか
です。
今回、VPS上で稼働するWebシステムから、数百〜1,500通規模のメールを送信する要件があり、Amazon Simple Email Service(Amazon SES)を使ったメール配信環境を構築しました。
その過程では、SMTP設定だけではなく、
- SPF
- DKIM
- DMARC
- MAIL FROM
- DNS
- 送信レート
- Queue
- バウンス
- 苦情
- AWS IAM
まで考える必要がありました。
この記事では、Amazon SESの単純な設定手順ではなく、システムからメールを送るときに、設計段階で何を考えるべきなのかを、実際の導入経験をもとに整理します。
「メールが送れた」と「メールが届いた」は違う
メール機能を開発するときに、まず理解しておきたいのがここです。
アプリケーションからSMTPサーバーにメールを渡せたとしても、
GmailやYahoo!メールなどの受信トレイに届くとは限りません。
メールが届くまでには、複数の段階があります。
アプリ
↓
SMTPサーバー
↓
インターネット
↓
受信側メールサーバー
↓
迷惑メール判定
↓
受信トレイ
特に現在は、送信元ドメインの認証や送信元の評価が重要です。
GoogleではGmail宛のメール送信について、SPFやDKIMなどの認証を求めています。
さらに、大量送信者にはSPF・DKIM・DMARCなど、より厳しい要件が設定されています。
つまり、
PHPやLaravelからメール送信処理が成功したからOK
ではありません。
なぜVPSに自前のメールサーバーを立てなかったのか
今回、新しいシステムの実行環境はVPSでした。
そのため、
VPSにPostfixなどのMTAを立てればよいのでは?
という選択肢もありました。
しかし、企業向けシステムで「大手フリーメールにもできるだけ安定して届けたい」という要件を考えると、自前運用には多くの課題があります。
VPSでは25番ポートが自由に使えるとは限らない
迷惑メール対策のため、VPS事業者によっては外向きの25番ポートを制限しています。
解除申請が必要になるケースもあります。
VPSのIPアドレスには過去の評価が存在する
自分たちが初めて使うIPアドレスであっても、そのIPアドレス帯自体には評価があります。
VPSやクラウド事業者のIPアドレス帯は、迷惑メール対策上、厳しく見られる場合もあります。
DNSや送信認証まで自分たちで管理する必要がある
到達率を高めるには、SMTPサーバーを動かすだけでは不十分です。
少なくとも、
- SPF
- DKIM
- DMARC
- PTR
- MAIL FROM
などを考える必要があります。
バウンスや苦情も自分たちで処理する必要がある
存在しないメールアドレスへ送信を続けたり、迷惑メール報告が増えたりすると、送信元の評価が下がります。
つまり自前運用では、
SMTPサーバーを構築すること以上に、送信元としての評価を維持することが大変
です。
そのため今回は、メール配信そのものを専門サービスへ任せる方針にしました。
業務用メールサーバーから大量送信する方法も避けた
もう一つ考えられるのが、会社で普段利用しているメールサーバーから送信する方法です。
しかし、これも慎重に考える必要があります。
普段のメールサーバーでは、
- 社員同士のメール
- 営業メール
- 問い合わせ返信
- 取引先とのメール
などを送信しています。
そこから突然、大量のシステム通知を送ると、通常業務のメールまで送信評価の影響を受ける可能性があります。
そのため今回は、
業務メールとシステム通知メールの送信基盤を分離する
という考え方を取りました。
Amazon SESとは
Amazon SESは、AWSが提供しているメール送受信サービスです。
システムから、次のような形でメールを送信できます。
アプリケーション
↓
Amazon SES
↓
Gmail / Yahoo! / Outlookなど
主な送信方法は、
- SMTP
- AWS API
の2種類です。
また、メール送信だけではなく、
- DKIM
- カスタムMAIL FROM
- バウンス管理
- 苦情管理
- サプレッションリスト
- 送信クォータ
- 送信状況の監視
など、メール配信に必要な仕組みが用意されています。
Amazon SESをおすすめしやすい理由
Amazon SESがすべてのケースで最適というわけではありません。
ただし、
Webシステムからトランザクションメールや一定量の通知メールを送る
用途では、非常に使いやすいサービスです。
SMTPでもAPIでも利用できる
既存システムへの変更を少なくしたければSMTP。
AWSとの連携を深くしたければAPI。
という選択ができます。
既存アプリケーションへの影響を最小限にできる点は、大きなメリットです。
AWS環境との相性が良い
SESは、
- IAM
- CloudWatch
- SNS
などAWSのサービスと組み合わせやすくなっています。
すでにAWSを利用しているシステムであれば、権限管理や監視をまとめやすいのも利点です。
従量課金で利用できる
SESには従量課金の料金体系があります。
そのため、
- 普段は数十通
- 特定タイミングで数百〜数千通
といったシステムとも相性が良いです。
固定費の大きなメール配信サービスよりも、利用量に応じてコストを管理しやすいケースがあります。
メール到達率を考えるための仕組みが揃っている
メール配信では、
- SPF
- DKIM
- DMARC
- MAIL FROM
- バウンス
- 苦情
- レピュテーション
を考える必要があります。
SESには、それらを管理するための仕組みが用意されています。
そのため、
自分たちでメールサーバーを運用するのではなく、メール配信基盤を利用する
という構成にできます。
今回はAPIではなくSMTP方式を選んだ
今回、特に興味深かったのがこの部分です。
当初は、LaravelからAmazon SESを利用するため、
LaravelのSESドライバを使えば、ほとんどコード変更なしで利用できる
と考えていました。
しかし実際にプロジェクトを調査すると、Laravelの構成変更時にSES用の依存パッケージを削除していました。
必要となる、
symfony/amazon-mailer
aws/aws-sdk-php
なども入っていません。
その状態でSESドライバを指定すると、当然エラーになります。
そこで今回は、
Laravel
↓
SMTP
↓
Amazon SES
という構成にしました。
アプリケーション側から見ると、
SMTPサーバーの接続先が変わっただけ
という状態になります。
結果として、メール送信ロジックへの変更を最小限にしながら、SESへ移行できました。
既存システムではSMTP方式が有力なことも多い
新規開発であれば、SES APIを直接利用する方法もあります。
一方で、
- すでにSMTP送信機能がある
- LaravelなどのMail機能を使っている
- アプリケーションへの変更を減らしたい
- 将来的に別の配信サービスへ変更できる余地を残したい
といったケースでは、SMTPは非常に実用的です。
アプリケーション
↓
SMTPインターフェース
↓
Amazon SES
という形にしておけば、アプリケーションとメールサービスをある程度分離できます。
SESのSMTP認証情報とIAMアクセスキーは別物
ここは非常に混同しやすいポイントです。
Amazon SESでSMTP接続するときに使用する認証情報は、通常のIAMアクセスキーをそのまま利用するものではありません。
つまり、
- AWS管理画面にログインするための認証
- アプリケーションからSESへSMTP接続する認証
は分けて考える必要があります。
メール設定時には、この違いを理解しておくことが重要です。
到達率を考えるならSPF・DKIM・DMARCを理解する
今回の要件では、
Gmailなど大手フリーメールへできるだけ安定して届ける
ことが重要でした。
そのため、
- SPF
- DKIM
- DMARC
を設定しました。
SPFとは
SPFは、
このドメインからメールを送信してよいサーバーはどこか
をDNSで宣言する仕組みです。
ただし、Amazon SESでは少し注意が必要です。
「SPFにamazonses.comを追加すればよい」だけではない
ここは今回、特に分かりにくかったポイントです。
Amazon SESは標準状態では、MAIL FROM、いわゆるReturn-PathにAmazon側のドメインを利用します。
そのため、単純に自社ドメインのSPFへ、
include:amazonses.com
を追加すればすべて解決する、という話ではありません。
そこで登場するのが、
カスタムMAIL FROM
です。
MAIL FROMとは何か
メールには、実は複数の「差出人」があります。
普段ユーザーが見るのは、
From:
info@example.jp
です。
一方で、メール配送システム内部では、
- MAIL FROM
- Return-Path
- Envelope From
と呼ばれる別の送信元情報が使われます。
たとえば、
From:
notice@example.jp
MAIL FROM:
bounce.mail.example.jp
といった構成です。
※上記ドメインは説明用です。
カスタムMAIL FROMには専用サブドメインを使う
SESでカスタムMAIL FROMを設定するときは、専用サブドメインを用意します。
概念的には、
bounce.mail.example.jp
などです。
そこへ、
- MXレコード
- SPF用TXTレコード
を設定します。
重要なのは、
通常のメール受信用サブドメインと共用しない
ことです。
差出人として使うサブドメインと、MAIL FROMに使うサブドメインも混同しやすいため、設計時に分けて整理しておくとよいでしょう。
DKIMはEasy DKIMを利用した
DKIMは、
このメールが確かにこのドメインから送信され、途中で改ざんされていない
ことを確認する仕組みです。
Amazon SESにはEasy DKIMが用意されています。
SESから指定されたCNAMEレコードをDNSへ設定することで、DKIM署名を利用できます。
今回もEasy DKIMを利用しました。
最終的には実際にメールを送信し、メールヘッダーを確認して、
dkim=pass
spf=pass
dmarc=pass
となるところまで確認しました。
SESの管理画面だけではなく、
実際に受信したメールのヘッダーまで確認する
ことが重要です。
DMARCはいきなりrejectにしなくてもよい
DMARCでは、SPFやDKIMの認証に失敗したメールをどう扱うかを指定します。
代表的な設定は、
p=none
p=quarantine
p=reject
です。
既存ドメインへ初めてDMARCを導入する場合、いきなりrejectにすると、既存のメール送信システムまで影響を受ける可能性があります。
そのため今回は、
p=none
として、まず監視から開始しました。
ただし注意したいのは、
DMARCを設定すれば必ず受信トレイに届くわけではない
ということです。
メール到達率には、
- 送信元評価
- バウンス率
- 苦情率
- 配信頻度
- メール本文
- 送信量の変化
なども関係します。
少量送信でもSPF・DKIM・DMARCを整えておく
今回想定していた配信数は、数百〜1,500通程度です。
大量送信者向けの基準に届かないケースもあります。
それでも、
- SPF
- DKIM
- DMARC
は最初から設定しました。
理由は、
配信数が増えてから直すより、最初から正しい構成にしておいた方がよい
からです。
メール送信基盤は、後から変更すると影響範囲が大きくなります。
将来的に配信数が増える可能性があるシステムほど、最初に整備しておく価値があります。
盲点だったのが「メールを送りすぎる問題」
今回、特に重要だったポイントの一つです。
Amazon SESには、
- 24時間あたりの送信可能数
- 1秒あたりの送信可能数
という送信クォータがあります。
そして実際には、
SESよりアプリケーション側の処理速度の方が速い
ことがあります。
今回、アプリケーション側の配信ループだけを測定すると、毎秒数百件を処理できました。
しかしSES側には送信上限があります。
つまり、
1,500人
↓
foreach
↓
即時送信
のような処理をすると、一気にSESへリクエストが飛んでしまいます。
上限を超えれば、スロットリングが発生します。
メール配信ではQueueを設計する
そこで今回は、
メール1通 = Job 1件
としてQueueへ積む設計にしました。
1,500件の送信依頼
↓
Queue
↓
Worker
↓
一定速度で取り出す
↓
Amazon SES
こうすることで、
- Webリクエストを待たせない
- SESのレート制限を守る
- エラー時に再実行しやすい
といったメリットが得られます。
Laravelであれば、
queue:work --rest=...
などを利用して送信間隔を制御できます。
Workerを増やすと送信速度も増える
ここも注意が必要です。
たとえば1Workerが毎秒10通になるよう調整しても、
Worker A:10通/秒
Worker B:10通/秒
Worker C:10通/秒
とすれば、全体では毎秒30通になります。
つまり、
レート制限はWorker単体ではなくシステム全体で考える
必要があります。
大量メール送信では、
どの配信サービスを選ぶか
より先に、
どこで流量を制御するか
を決めておくことが重要です。
sync Queueは大量送信には向かない
Laravelには、
QUEUE_CONNECTION=sync
という設定があります。
これはJobをその場で実行するため、開発時には便利です。
しかし大量送信では、
リクエスト
↓
メール1
↓
待機
↓
メール2
↓
待機
↓
...
となってしまいます。
そのため、数百〜数千通を扱うのであれば、
RedisやDatabaseなどの永続Queue + Worker
という構成を検討した方がよいでしょう。
SESの送信上限はアカウントごとに確認する
Amazon SESの送信上限は、全ユーザー共通の固定値ではありません。
送信クォータは、
- AWSアカウント
- リージョン
- 本番アクセス状況
などによって異なります。
そのため、
SESなら毎秒○通送れる
と決め打ちして実装するべきではありません。
実際に割り当てられている、
- Sending quota
- Maximum send rate
を確認し、それに合わせてQueue側の設定を調整する必要があります。
不達・苦情をどう扱うかも設計する
メール送信後には、
- メールアドレスが存在しない
- メールボックスが無効
- 受信者が迷惑メール報告した
といったことが発生します。
これらを無視して送信し続けると、送信元の評価に影響します。
Amazon SESには、バウンスや苦情が発生したアドレスへの再送信を抑制する仕組みがあります。
そのため今回は、
最初からすべてを自社アプリケーション側で管理しない
という方針を取りました。
より高度に管理する場合には、
Amazon SES
↓
Bounce / Complaint
↓
SNSなど
↓
自社DB
という構成も考えられます。
ただし、その分だけ開発・運用コストも増えます。
システムの要件に応じて段階的に導入するのがよいでしょう。
実際に設定してみて苦労したのはDNSだった
SES自体の設定以上に、実際にはDNSの確認に時間がかかりました。
「DNSを追加しました」が本当に公開されているとは限らない
今回、先方から、
SPFを追加しました
と連絡を受けました。
しかし公開DNSを確認すると、反映されていませんでした。
調査すると、
DNSを管理している事業者とメールサーバー事業者が別だった
ことが原因でした。
企業のドメインでは、
ドメイン取得会社
DNS管理会社
Webサーバー会社
メールサーバー会社
がそれぞれ異なるケースがあります。
そのためDNSを変更するときには、
現在どのネームサーバーが権威DNSなのか
を最初に確認した方がよいでしょう。
管理画面ではなく公開DNSを確認する
DNS設定では、
管理画面に入力されている
ことと、
インターネット上からその値を取得できる
ことは別です。
そのため、
dig
nslookup
などを使って、公開されているDNS情報を確認する必要があります。
今回も既存TXTレコードの中に、DNS管理画面の項目名のような文字列が値へ混ざっているレコードが見つかりました。
DNSは、
登録されているかではなく、正しく公開されているか
まで確認することが重要です。
CloudWatchの監視でも少しハマった
SESの状態をCloudWatchで監視しようとした際にも、少しハマりました。
まだメール送信実績がない状態では、対象となるメトリクスが表示されませんでした。
そこで、
- テストメールを送信
- SESのメトリクスを発生させる
- CloudWatch側で確認
- アラームを作成
という流れにしました。
AWSサービスでは、
実際にイベントが発生してからメトリクスが現れる
ケースがあります。
監視設定をするときに覚えておくとよいポイントです。
AWSアカウントそのもののセキュリティも重要
今回、メール送信の設定とは別に、AWSアカウントの管理についても確認する必要がありました。
たとえば、
- AdministratorAccessが付与されている
- MFAが設定されていない
- パスワードが平文で共有されている
といった状態で作業を進めるのは危険です。
そこで、
メール関連の作業だけを行う専用ユーザー
を作成し、必要な権限だけを付与する方向に変更しました。
外部の開発会社へAWS作業を依頼するときも、
AdministratorAccessを渡す
のではなく、
必要なIAM権限のみ付与
MFAを利用
作業終了後に権限を削除
といった運用が望ましいでしょう。
SESのAWSアカウントは誰の名義にするべきか
今回、Amazon SESは顧客側のAWSアカウントで構築しました。
これは非常に重要だと考えています。
理由は、
- 利用料金を負担するのは顧客
- SPF・DKIMを設定するのは顧客のドメイン
- 送信ドメインの評価は顧客の資産
- 保守契約が終了してもメール基盤は残る
からです。
開発会社側のAWSアカウントへSESを作ってしまうと、契約終了時に、
ドメイン
DNS
認証
送信評価
メール基盤
の移管を考えなければなりません。
外部サービスを利用するときには、
そのサービスのアカウントを最終的に誰が所有するべきか
まで考える必要があります。
これはAmazon SESに限らず、SaaSやクラウドサービス全般に言えることです。
Amazon SESを使えば必ずメールが届くわけではない
ここも重要です。
SESを利用し、
SPF PASS
DKIM PASS
DMARC PASS
となっていても、
必ず受信トレイに入る
ことを保証するものではありません。
メールの到達率には、
- 送信元レピュテーション
- バウンス率
- 苦情率
- メール本文
- 配信頻度
- 急激な送信量の増加
- 受信者との関係
- 登録解除方法
など、多くの要素があります。
Amazon SESは、
届くメールを作るための基盤
と考えるのがよいでしょう。
Amazon SESが向いているケース
今回の経験から、Amazon SESは特に次のようなシステムと相性が良いと感じています。
- 会員登録メール
- パスワード再設定
- 予約確認
- システム通知
- 試験・イベント案内
- 数百〜数千件規模の一括通知
- AWSを利用しているWebシステム
- Laravelなど既存システムからSMTP送信したいケース
一方で、
- HTMLメールをノーコードで頻繁に作りたい
- マーケティング担当者自身が配信したい
- ステップメールを組みたい
- 顧客セグメントをGUIで管理したい
- MAやCRMとして利用したい
といった用途では、マーケティングメール向けのサービスの方が適している場合があります。
重要なのは、
SESが優れているかではなく、自社のメール送信要件に合っているか
です。
メール送信機能を作るときのチェックポイント
システムへメール送信機能を追加するときは、最低でも次の観点を確認しておくとよいでしょう。
| 分類 | 確認すること |
|---|---|
| 用途 | 仮登録、通知、一括配信、マーケティングのどれか |
| 件数 | 1日最大何通送るのか |
| 瞬間量 | 一度に何件送信する可能性があるか |
| 配信サービス | SESなど外部サービスを利用するか |
| 接続方法 | SMTPかAPIか |
| Queue | 非同期送信するか |
| レート制御 | どこで毎秒送信数を制御するか |
| SPF | 正しく設定されているか |
| DKIM | 署名できているか |
| DMARC | ポリシーを設定しているか |
| MAIL FROM | 独自ドメインを利用するか |
| DNS | 権威DNSはどこか |
| バウンス | 不達アドレスをどう処理するか |
| Complaint | 苦情をどう処理するか |
| 監視 | エラーや送信状況を監視できるか |
| アカウント | 誰がサービスを所有するか |
| IAM | 必要最小限の権限になっているか |
「メールを送る」という一つの機能だけでも、実際にはこれだけの設計項目があります。
まとめ:メール機能は「送信処理」ではなく「配信基盤」として考える
今回Amazon SESを導入して、改めて感じたのは、
メール機能は単なるプログラムの送信処理ではない
ということです。
単純に考えれば、
アプリ
↓
SMTP
↓
送信
です。
しかし企業システムとして考えると、
アプリケーション
↓
Queue
↓
レート制御
↓
Amazon SES
↓
SPF / DKIM / DMARC
↓
受信サービス
↓
Bounce / Complaint
↓
監視・改善
までがメール送信機能です。
今回特に重要だったのは、次のポイントです。
- 到達率が重要なら、自前MTAを安易に選ばない
- 既存システムではSMTP方式がシンプルなこともある
- SPFだけでなくDKIM・DMARC・MAIL FROMまで考える
- アプリケーション側で送信レートを制御する
- 大量配信はQueueを前提にする
- 不達・苦情まで含めて運用を設計する
- DNSは管理画面ではなく公開状態を確認する
- クラウドアカウントと送信ドメインの評価は顧客の資産として扱う
Amazon SESは、これらをすべて自前で構築することなく、メール配信基盤として利用できるサービスです。
特に、
普段は数十通だが、特定のタイミングでは数百〜数千通送りたい
という業務システムでは、有力な選択肢になります。
メール送信機能を設計するときには、
どう送るかではなく、どう安全に、継続的に届けるか
から考えることが重要です。