SESでメールを送るときの注意点
Date2026/05/29 Last Modified2026/05/29
メールというのは非常に身近で、簡単で便利な仕組み……と思っていたのは技術者になる前のこと。
最近ではメールにまつわるあれこれが、複雑で厄介な仕組みであることを知って苦戦している。
今回はSESを用いた実装で、つまずいた点をまとめていきたい。
概要
実装要件は以下のような感じ。
「顧客リストをシステムに送付するので、そのメールアドレス宛に自動でメール送信してほしい。アドレスが間違ってたら管理者にメールで教えてね」
聞いた感じは簡単そうだが、その裏では色々な処理が待ち受けていた。
環境
- AWS EC2(AmazonLinux2023) + MySQL
- Amazon SES
- Laravel12(PHP8.2)
メールの妥当性をどう検証するのか
メールの送信成功を判定するときに使うのはSESからのSMTPリクエストである。
SMTPリクエスト上で、存在しないドメインに対してのレスポンスは550エラーであり、成功は250ステータスで表される。
ここでの550エラーは恒久的な失敗を表すので確実にアドレス間違いだとわかるのだが、「250 OK またはSESからのAPI成功」の場合については少し厄介である。
そもそも、250 OKというのは通信上の成功を表しているだけであり、メールボックスへの到達を表しているわけではない。
ドメインパートが正しい場合、大抵のリクエストは成功扱いになるが、ローカルパートが存在しなかった場合は非同期でバウンス通知として処理される。
SESを利用している場合、バウンス通知はSES宛に届くためシステムが直接的に受け取れず、処理にひと手間かかるというわけだ。
歴史的背景と完全には拾いきれないバウンス
なぜリクエストは成功扱いなのに、実際のメールアドレス到達はできなくて返ってくるという面倒なプロセスがあるのか。
その一つとして、メールアドレスの存在確認を行うスパム攻撃があった。
あらゆるローカルパートに対してメールを送信することにより、実存するメールボックスを探し当てるという方式で、同期的にレスポンスしてしまうことで素早い攻撃が可能となっていた。
その対策として「一度250 OKで処理してあとでバウンスする」という方式が取られた事情がある。
これはあくまで一例であり、システムの可用性を含めて様々な理由で非同期的な存在チェックが行われる背景があるため、250 OKはそのまま成功とはいえず、正しい到達率を見るためにはバウンスを見る必要がある。
しかし、バウンスが必ずしも返ってこないという問題がある。
その一つは「backscatter攻撃」である。
これは、リクエスト時のMAIL FROM宛にバウンスを返すという機能を利用して大量にバウンスメールを送ってオーバーフローさせるという攻撃である。
MAIL FROMは簡単に偽装できてしまうので、スパムメールが疑われるものはバウンスしない扱いにするという運用になっている。
また、大規模メールサーバーになるとバウンス件数が大量になることもあり、運用負荷軽減のためにバウンスをサイレントで破棄することもあり得る。
こういった背景から、バウンスを見れば100%メールアドレスの有効性が拾えるかと言えば否であり、システムで保証できる線引きはどこまではを明示する必要がある。
バウンスを効果的に拾うためのシステム
今回の実装はLaravel + SESによってメール送信をする仕組みである。
このうち、バウンスメールは非同期的にSESに蓄積されるため、なんらかの方法で取り出してLaravelへ返す必要がある。
ここで辿り着いた方式の一つは
「Amazon SNS + Lambda + API」である。
具体的にはSESに来たバウンス通知をSNSで拾い、それらをLambdaが非同期でLaravelのエンドポイント宛に投下、Laravelは管理者への通知リストへ保存して、日次のバッチ等でサルベージする形になる。
このケースだとLambdaからのリクエストが細切れになって来るが、Lambdaから一度DynamoDBまたはRDSへ蓄積して一気にLaravelへリクエストするという方式もあり一長一短である。
また、bounceにはPermanent bounce / Hard bounceとTransient bounce / Soft bounceという概念があり、存在しないまたは拒否によって失敗したHard bounceと、一時的な失敗で再送すれば成功の可能性があるものがSoft bounceである。
これらの状態を管理して、Soft bounceの場合は再送を行うという仕組みを組んでおけばよい。
これによって、
ドメインが存在しない等のエラーは同期的に拾いあげ、バウンスによるエラーも非同期的にできる限り拾い上げるというシステムが完成した。
ちなみにバウンスがたまりすぎると勝手にSESは送信機能を停止してしまうので、何でもかんでもメールリストを受け付けるのではなくて、リスト作成時のアナログの時点で管理も必要である。(改善方針を伝えないといけなくて面倒なことになる)
まとめ
「メールが間違ってたら教えてね」という単純な仕様だったが、深堀してみると面白い。
実際にメールソフトなどを使って実験してみると、存在しないドメインはすぐにエラーが返ってきたが、存在するドメインは翌日にエラーが返ってきたりした。
こういった100%を解決できないようなシステムは、「今まで現場ではどうやっていたか」や「一般的なシステムはどう処理しているか」などの様々な観点から、コストを勘案しつつ実装を考えていくのが良いと学んだ。
今回はバウンスにまつわる話だが、ドメインの取得が絡んでくるとSPFやらメールそのものを判定する技術の方も必要になって来るので、改めてメールというのは思ったほど単純じゃないなという感想。