Amazon SES による Amazon SNS へのバウンス通知をサブスクリプションフィルターポリシーでフィルタリングしてみた
コンバンハ、千葉(幸)です。
Amazon SES によるメール送信時にバウンスが発生した場合、その内容を Amazon SNS トピックに通知できます。
SNS トピックにはメールアドレスなどのエンドポイントをサブスクライブでき、サブスクライブ先にメッセージを送信するかどうかをサブスクリプションフィルターでフィルタリングできます。
バウンスの内容によって SNS トピックによる通知の有無をコントロールしたい機会がありましたので、実際に試してみました。
今回やりたいこと
以下のイメージです。
- Amazon SES によるテストメール送信(Amazon SES メールボックスシミュレーター)で意図的にバウンスを発生させる
- バウンスのタイプは
Permanent
とし、以下の2種類のバウンスサブタイプを発生させるGeneral
OnAccountSuppressionList
- 送信に使用するアイデンティティではフィードバックメール転送を有効にし、どちらのバウンスでも E メール転送を行う
- 送信に使用するアイデンティティでは
Bounce
タイプでの SNS トピックへのフィードバック通知を有効にする - 通知先の SNS トピックには E メールエンドポイントをサブスクライブし、サブスクリプションフィルターを設定する
- サブスクリプションフィルターを変更しながら通知の有無を確認する
テストメール送信って何?フィードバックメール転送/フィードバック通知って何?といった場合は、以下のエントリにて補足説明しておりますのであわせてご参照ください。
Amazon SES テストメール送信で意図的にバウンスを発生させる
今回は以下の宛先にテストメール送信をすることでバウンスを発生させます。
# | 宛先 | bounceType | bounceSubType |
---|---|---|---|
1 | ドメインは存在するがユーザーが存在しないメールアドレス | Permanent | General |
2 | サプレッションリストに登録されたメールアドレス | Permanent | OnAccountSuppressionList |
#1 については、宛先のドメインによってはbounceSubType
がGeneral
になるとは限りません。その場合は Amazon SES メールボックスシミュレーターのシナリオで「バウンス」を選択するとよいでしょう。
#2 については、以下の画面のサプレッションリストに追加されたメールアドレスに送信することで発生させます。
サプレッションリストには 3 つのタイプがあり、上記の画面はアカウントレベルのものを表します。
タイプ | 管理主体 | 範囲 |
---|---|---|
グローバルサプレッションリスト | Amazon SES | グローバル |
アカウントレベルのサプレッションリスト | カスタマー | AWS アカウント |
設定セットレベルのサプレッション | カスタマー | 送信単位 |
下に行くほど上位のタイプを上書きします。
参考:Amazon Simple Email Service でのリストとサブスクリプションの管理 - Amazon Simple Email Service
今回は一度 #1相当の操作を行うことで、宛先のメールアドレスをアカウントレベルのサプレッションリストに自動的に追加させました。手動でメールアドレスを指定して追加することもできます。
フィードバック通知コンテンツにおけるバウンスタイプ
Amazon SES のフィードバック通知により Amazon SNS に送信されるコンテンツの内訳は以下より確認できます。
特に、バウンスタイプについては以下のようにまとめられています。(ドキュメントの記述を一部省略して表現)
bounceType | bounceSubType | 説明 |
---|---|---|
Undetermined | Undetermined | Amazon SES がバウンスの理由を判断できるだけの十分な情報が含まれていない。 |
Permanent | General | 受取人の E メールプロバイダーがハードバウンスの原因を示していない。 |
Permanent | NoEmail | E メールアドレスが存在しない。 |
Permanent | Suppressed | 最近の履歴でハードバウンスを生じているため、Amazon SES サプレッションリストに追加されている。 |
Permanent | OnAccountSuppressionList | アカウントレベルのサプレッションリストにあるので、このアドレスへの送信を抑制した。 |
Transient | General | 受取人の E メールプロバイダーは一般的なバウンスメッセージを送信した。 |
Transient | MailboxFull | 受取人の受信トレイが満杯である。 |
Transient | MessageTooLarge | 受信したメッセージが大きすぎる。 |
Transient | ContentRejected | 受取人のプロバイダーが許可しないコンテンツが含まれていたた。 |
Transient | AttachmentRejected | 受取人プロバイダーが許容しない添付が含まれていた。 |
フィードバック通知のイベント例
実際にバウンスを発生させた際に Amazon SNS に通知されるイベントの中身の例を示します。
#1,#2 いずれの場合でも、以下のアドレスで例示します。
- 送信元アドレス:
source@example.co.jp
- 宛先アドレス:
dummy@example.com
#1 ドメインは存在するがユーザーが存在しないメールアドレス宛の場合
{ "notificationType": "Bounce", "bounce": { "feedbackId": "0106018adba7c81e-f2f2b895-154d-484e-9f3f-315d25f8e47a-000000", "bounceType": "Permanent", "bounceSubType": "General", "bouncedRecipients": [ { "emailAddress": "dummy@example.com", "action": "failed", "status": "5.1.1", "diagnosticCode": "smtp; 550-5.1.1 The email account that you tried to reach does not exist. Please try\r\n 550-5.1.1 double-checking the recipient's email address for typos or\r\n 550-5.1.1 unnecessary spaces. Learn more at\r\n 550 5.1.1 https://support.google.com/mail/?p=NoSuchUser fm12-20020a0566382b0c00b00439ca012a0bsi1271622jab.6 - gsmtp" } ], "timestamp": "2023-09-28T11:58:40.000Z", "reportingMTA": "dns; googlemail.com" }, "mail": { "timestamp": "2023-09-28T11:58:33.733Z", "source": "source@example.co.jp", "sourceArn": "arn:aws:ses:ap-northeast-1:000000000000:identity/source@example.co.jp", "sourceIp": "xx.xx.xx.xx", "callerIdentity": "cm-chiba.yukihiro", "sendingAccountId": "000000000000", "messageId": "0106018adba7ad05-442a1b86-342a-4ad2-afa8-1bb5559ca573-000000", "destination": [ "dummy@example.com" ] } }
#2 サプレッションリストに登録されたメールアドレス宛の場合
{ "notificationType": "Bounce", "bounce": { "feedbackId": "0106018adad9c5ba-69a5c1ac-4a4a-4b63-9025-b566f294eef5-000000", "bounceType": "Permanent", "bounceSubType": "OnAccountSuppressionList", "bouncedRecipients": [ { "emailAddress": "dummy@example.com", "action": "failed", "status": "5.1.1", "diagnosticCode": "Amazon SES did not send the message to this address because it is on the suppression list for your account. For more information about removing addresses from the suppression list, see the Amazon SES Developer Guide at https://docs.aws.amazon.com/ses/latest/DeveloperGuide/sending-email-suppression-list.html" } ], "timestamp": "2023-09-28T08:13:39.000Z", "reportingMTA": "dns; amazonses.com" }, "mail": { "timestamp": "2023-09-28T08:13:39.355Z", "source": "source@example.co.jp", "sourceArn": "arn:aws:ses:ap-northeast-1:000000000000:identity/source@example.co.jp", "sourceIp": "xx.xx.xx.xx", "callerIdentity": "cm-chiba.yukihiro", "sendingAccountId": "000000000000", "messageId": "0106018adad9c49b-b5d4adf9-124f-4eb7-8b86-577dbeb66f99-000000", "destination": [ "dummy@example.com" ] } }
参考:シミュレートの場合
{ "notificationType": "Bounce", "bounce": { "feedbackId": "0106018acc0eca6c-8485ea19-6287-4d21-8b4b-4827f401342e-000000", "bounceType": "Permanent", "bounceSubType": "General", "bouncedRecipients": [ { "emailAddress": "bounce@simulator.amazonses.com", "action": "failed", "status": "5.1.1", "diagnosticCode": "smtp; 550 5.1.1 user unknown" } ], "timestamp": "2023-09-25T11:17:16.000Z", "remoteMtaIp": "xx.xx.xx.xx", "reportingMTA": "dns; e234-4.smtp-out.ap-northeast-1.amazonses.com" }, "mail": { "timestamp": "2023-09-25T11:17:14.991Z", "source": "source@example.co.jp", "sourceArn": "arn:aws:ses:ap-northeast-1:000000000000:identity/source@example.co.jp", "sourceIp": "xx.xx.xx.xx", "callerIdentity": "cm-chiba.yukihiro", "sendingAccountId": "000000000000", "messageId": "0106018acc0ec66f-4368cf8d-8f73-4fe7-8435-e969e24b5e12-000000", "destination": [ "bounce@simulator.amazonses.com" ] } }
SNS サブスクリプションフィルターを設定する
今回メール送信に使用したアイデンティティでは、フィードバック通知先としてbounce-topic
という SNS トピックを指定しています。
bounce-topic
にはすでに特定のメールアドレスをサブスクライブ済みです。ここからサブスクリプションフィルターポリシーを設定してみます。
サブスクリプションフィルターポリシーについては以下を参照してください。
編集画面で設定をしていきます。サブスクリプションフィルターポリシーのスコープには「メッセージ属性」と「メッセージ本文」の2種類があります。Amazon SES のフィードバック通知においては「メッセージ属性」が存在しないため、「メッセージ本文」を選択する必要があります。
「bounceType: Permanent
かつbounceSubType: General
」の場合のみ許可、としたい場合には以下のように書きます。
{ "bounce.bounceType": ["Permanent"], "bounce.bounceSubType": ["General"] }
設定が保存されるとこのように確認できます。(ポリシーに改行が自動的に含まれていますね。)
ちなみに:ポリシーの書き方のパターン
以下は同じ設定内容を表します。
{ "bounce.bounceType": ["Permanent"], "bounce.bounceSubType": ["General"] }
{ "bounce":{ "bounceType": ["Permanent"], "bounceSubType" : ["General"] } }
どちらで書いてもポリシーとして有効です。 後者の方が自然な気がしますが、今回は前者の書き方で統一しています。(個人的な好みです。)
バウンスを発生させてみた
実際にメール送信を行いバウンスを発生させてみます。まとめるほどではないですが、以下の結果となりました。
# | bounceType | bounceSubType | フィードバックメール転送 | SNS フィードバック通知 |
---|---|---|---|---|
1 | Permanent | General | 届く | 届く |
2 | Permanent | OnAccountSuppressionList | 届く | 届かない |
フィードバック転送によるメールはサブスクリプションフィルターと関係ないので、以下のような形式で毎回届きます。
SNS フィードバック通知によるメール送信は意図通りフィルタリングされていました。
フィルタリングポリシー変更例1
フィルタリングポリシーを以下のように変更し、bounceType
のみを評価するようにしてみました。
{ "bounce.bounceType": ["Permanent"] }
結果はこのようになります。
# | bounceType | bounceSubType | フィードバックメール転送 | SNS フィードバック通知 |
---|---|---|---|---|
1 | Permanent | General | 届く | 届く |
2 | Permanent | OnAccountSuppressionList | 届く | 届く |
フィルタリングポリシー変更例2
以下のように変更し、「bounceType: Permanent
かつbounceSubType
が3つのうちのどれか」という条件にしてみました。
{ "bounce.bounceType": [ "Permanent" ], "bounce.bounceSubType": [ "General", "OnAccountSuppressionList", "NoEmail" ] }
結果は以下の通りです。
# | bounceType | bounceSubType | フィードバックメール転送 | SNS フィードバック通知 |
---|---|---|---|---|
1 | Permanent | General | 届く | 届く |
2 | Permanent | OnAccountSuppressionList | 届く | 届く |
フィルタリングポリシー変更例3
anything-but
キーワードを使用するパターンを試してみました。「bounceType: Permanent
かつbounceSubType
が2つ以外のどれか」という条件です。
{ "bounce.bounceType": [ "Permanent" ], "bounce.bounceSubType": [ { "anything-but": [ "Suppressed", "OnAccountSuppressionList" ] } ] }
結果は以下の通りです。
# | bounceType | bounceSubType | フィードバックメール転送 | SNS フィードバック通知 |
---|---|---|---|---|
1 | Permanent | General | 届く | 届く |
2 | Permanent | OnAccountSuppressionList | 届く | 届かない |
フィルタリングポリシー変更例4
最後に少し変わり種で、prefix
キーワードを用いたパターンを試してみました。diagnosticCode
がAmazon
から始まる場合は許可、という書き方にしたかったです。
{ "bounce.diagnosticCode": [ { "prefix": "Amazon" } ] }
結果としては意図したフィルタリングになりませんでした。イベント内のdiagnosticCode
にスペースが含まれているからかと思います。
# | diagnosticCode | フィードバックメール転送 | SNS フィードバック通知 |
---|---|---|---|
1 | smtp; 550-5.1.1 The email account that you tried ...(略) | 届く | 届かない |
2 | Amazon SES did not send the message to this address ...(略) | 届く | 届かない |
例えば以下のような指定であれば意図通りの結果となりました。
{ "bounce.bounceType": [ "Permanent" ], "bounce.bounceSubType": [ { "prefix": "On" } ] }
# | bounceType | bounceSubType | フィードバックメール転送 | SNS フィードバック通知 |
---|---|---|---|---|
1 | Permanent | General | 届く | 届かない |
2 | Permanent | OnAccountSuppressionList | 届く | 届く |
終わりに
Amazon SES によるバウンスのフィードバック通知を、Amazon SNS のサブスクリプションフィルターでフィルタリングしてみました。
イベントの中身がある程度はっきりしている場合には、こういった方法でフィルタリングすることで通知量が減らせ、本来検知したい内容をよりわかりやすく把握できるようになります。あるいは、サブスクリプションを複数作成することで、内容によって通知先を振り分けるということも実現できます。
ただ、例えばバウンスサブタイプNoEmail
が返ってくることを期待してフィルタリングを設定したが実際の環境ではGeneral
が返ってくる、といったケースもあるかもしれません。(バウンスメッセージは受信側のプロバイダーに依存する部分もあるため。)
決め打ちで指定せず、ある程度パターンが見えてからフィルタリングすることをおすすめします。
以上、 チバユキ (@batchicchi) がお送りしました。