サービス終了のお知らせが Amazon SES 停止の引き金になった話
はじめに
AWS上で運用していたウェブサービスのサービスクローズに伴い、全ユーザーへ「サービス終了のお知らせ」メールを送信しました。 すると、Amazon SES のバウンス率が跳ね上がり、アカウントからのメール送信機能が強制停止されてしまいました。
この記事ではレビュー通知を受けてからメール送信の停止、そして復旧までの経緯と、そこから得た教訓をまとめます。
経緯
レビュー通知
ある日、AWS から SES のバウンス率が 10% を超えたためアカウントがレビュー状態に入った、という通知が届きました。
過去に別件で同様の対応をしたことがあったため、落ち着いて調査と対応を進めようとしていたのですが……
送信停止
間もなく、バウンス率が 17% を超えたため送信機能を停止した、という追加の連絡が来ました。レビュー期間中に状況が改善するどころか悪化したと判断されたようです。こうなると、AWS サポートへ原因の報告と改善計画を提出して承認されるまで Amazon SES 経由でメールを送信できません。 即時対応が必要な状況に変わりました。
問題の調査と原因
調査をしたところ、AWSからの通知の直前にサービスクローズに伴う利用者へのメール一斉送信を行っていたことが判明しました。 CloudWatch メトリクスを見てもバウンスレート上昇のタイミングと、このメールの送信時間とが一致しており、原因ははっきりとしました。
そして、このオペレーションによってバウンスレートが一気に上昇した理由は明快で、「普段メールを送っていないユーザーにもメールを一斉送信した」ことに尽きます。
通常運用では、アクティブユーザーに対してメールを送信しており、バウンスが発生するようなアドレスはほぼ含まれていませんでした。 また、SES 利用のプラクティスに則り、サプレッションリストを有効にしているので、仮に無効なアドレスにメールを送信したとしても、2回目以降の同一アドレスへのバウンスは発生しない状態になります。
しかし、今回はサービス終了という性質上、普段サービスを利用していないユーザーにも告知が必要であり、結果として、長期間メンテナンスされていないメールアドレス——既に削除・無効化されたアドレスを大量に含むリスト——に対して一斉送信を行うことになりました。
これらのアドレスがハードバウンスとなり、バウンス率が一気に跳ね上がりました。
対応
AWS への申請
SES の送信停止時、AWS から届く通知には対応用のサポートケース URL が記載されています。このケースに対して、以下の内容を回答しました。
- 原因:サービス終了のメール送信を行ったが、そのオペレーションの性質上、非アクティブユーザーを含む全ユーザーに一斉送信を行ってしまった。 その中に古いメールアドレスが多くあり、短期間でハードバウンスが大量に発生した。
- 実施済みの対策:アカウントレベルのサプレッションリストを有効化済みで、バウンスしたアドレスは自動的に除外されている
- 再発防止:同様の一斉送信を再度行う予定はない。サービス自体が近くクローズ予定であり、今後の送信量は限定的
なお、AWS サポートは日本語に対応しているため、通知が英語で届いても日本語で回答して問題ありません。
復旧
今回は結果的に SES の復旧を待つ判断を取りました。サービス上でメールを利用する場面が限定的で、利用者への影響がほとんどなかったこと、またトラブル翌日が休日で、サービスの性質上ほぼ利用されない日だったことが理由です。
並行して SES 以外のメールリレーサーバーの準備にも着手していましたが、申請から約 10 時間後(翌日の早朝 4 時ごろ)に送信機能が復旧され、こちらは取り越し苦労で終わりました。とはいえ、復旧が保証されているわけではないので、代替手段を用意しておくこと自体は悪い判断ではなかったと思います。
反省と教訓
バウンス率は「割合」で評価される
SES のバウンス率はメール送信数に対するハードバウンスの割合として、直近の送信をローリングで計算されています。AWS が問題視するのはバウンスの「件数」ではなく「率」です。
今回のシステムは普段の送信量が少ないものでした。そのため、サービス終了メールの送信がカウントの大半を占めてしまい、バウンスの絶対数がそれほど多くなくても率としては致命的な数字になりました。1 日に数万通送っているようなシステムであれば、同じ件数のバウンスでも率としては数 % で収まっていたはずです。これは送信量の少ないシステム特有の落とし穴と言えます。
メールアドレスの事前検証は現実的に難しい
再発防止に際して、送る前にメールアドレスが有効かどうかを確認できるかを改めて調査しました。 これは、技術的には SMTP の RCPT TO コマンドでアドレスの存在を確認する方法が存在します。 しかし、この仕組みは有効なアドレスの収集(ハーベスティング)に悪用できるため、現在の主要なメールプロバイダーでは利用できません。例えば、Gmail は存在しないアドレスでも 250 OK を返しますし、Microsoft 系も同様の対策を取っています。
ZeroBounce や NeverBounce といったサードパーティのバリデーションサービスも存在しますが、こちらを使っても「メールアドレスが有効か否か」をメールを送信することなく判断することはできません。
つまり、長期間放置されたアドレスリストに対して「送る前に無効なアドレスを完全に除外する」現実的な手段は存在しません。
今回のようなケースで実施すべきだったこと
メールアドレスの検証手段がない以上、「バウンスが発生すること」を前提にした送信設計が必要でした。具体的には以下のアプローチを取るべきでした。
- 送信順序を工夫する:アクティブユーザーへの送信を先に行い、十分な送信実績(分母)を作ってから、非アクティブユーザーへの送信を混ぜていく
- バッチ分割:一括送信ではなくバッチに分け、途中のバウンス率をモニタリングしながら送信ペースを調整する
- ローリング計算を意識する: SES のバウンス率は直近の送信に対して計算されるため、1 日あたりの「リスクのある送信」の比率をコントロールし、正常な送信で率を希釈する
バウンスの絶対数を減らすことはできなくても、そのレートをコントロールすることはできました。そこに気づけていれば、今回のSESのレビュー入り/停止といった状況は防げたことが反省です。
まとめ
今回の件は「正当な目的のメールであっても、その送り方を間違えれば SES は止まる」という教訓でした。特に送信量が少ないシステムでは、一度の一斉送信がバウンス率に与えるインパクトが大きくなります。
サービス終了の告知のように、普段送らない相手にメールを送る必要がある場面は、どのサービスにもいつか訪れます。その時に慌てないためにも、「未知のアドレスリストへのメール一括送信はバウンス率への影響を前提に設計する」というプラクティスを覚えておくと良いと思います。


















