AWS SES サプレッションリストによるメール未着を調査・解消した
AWS SES サプレッションリストによるメール未着を調査・解消した
まとめ
- SES のサプレッションリストはリージョンごとに独立している。正しいリージョンを確認すること
- Hard Bounce が発生すると SES がアドレスを自動的にサプレッションリストに登録し、以降の送信がすべてブロックされる
- サプレッションリストから削除してもブロックされたメールは再送されない。手動で再送が必要
現象
あるユーザーへの招待メールをはじめ、OTP メールなど複数種類のメールがまったく届かない事象が発生した。
調査
SES サプレッションリストを確認
aws sesv2 get-suppressed-destination \
--email-address {メールアドレス} \
--profile {profile} \
--region ap-northeast-1登録されていた。登録日時と理由(BOUNCE)も確認できた。
注意: SES のサプレッションリストはリージョンごとに独立している。最初に誤ったリージョンで確認して “NotFoundException” が返っても、他のリージョンに登録されている可能性がある。Terraform の aws_ses.tf で # Main region コメントを確認してから実行すること。
CloudWatch Logs で SMTP エラーコードを確認
SNS → アプリ webhook の経路で受け取ったバウンス通知が Rails ログに記録されていた。
filter-pattern: "Bounce"で絞り込むと、初回バウンス時の SMTP 診断コードが確認できた:
status: 5.3.0
diagnosticCode: smtp; 550 Invalid recipient (#5.1.1)5.1.1 = 宛先アドレスが受信サーバーに存在しない。ドメイン側のポリシー拒否ではなく、アドレスそのものが未存在だったことが確定した。
根本原因
招待メールを送った時点で、受信側のメールサーバーにそのアドレスが存在していなかった(アカウント未プロビジョニング)。受信サーバーが 550 Invalid recipient を返し、SES が Hard Bounce として判定してサプレッションリストに自動登録した。
以降の全メールは OnAccountSuppressionList でブロックされ続けた。
対応
# 確認(readonly プロファイル)
aws sesv2 get-suppressed-destination \
--email-address {メールアドレス} \
--profile {readonly-profile} \
--region ap-northeast-1
# 削除(書き込みプロファイル)
aws sesv2 delete-suppressed-destination \
--email-address {メールアドレス} \
--profile {write-profile} \
--region ap-northeast-1削除後、メール送信が正常に届くことを確認。ただし削除してもブロックされていたメールは再送されないため、招待メールなど重要なメールは手動で再送が必要。
ドメイン単位での確認方法
同ドメインの他アドレスがサプレッションリストに含まれていないか一括確認できる:
aws sesv2 list-suppressed-destinations \
--profile {readonly-profile} \
--region ap-northeast-1 \
| jq '[.SuppressedDestinationSummaries[] | select(.EmailAddress | contains("example.com"))]'