Amazon SESのバウンス発生時、EventBridgeとStep Functions経由でメール通知してみた

Amazon SESのバウンス発生時、EventBridgeとStep Functions経由でメール通知してみた

2025.07.25

はじめに

Amazon SESでメール送信を行った際に発生するバウンス(送信したメールが何らかの原因で相手に届かず、送信者の元に返送されてくる現象)を検知し、管理者に通知する仕組みを構築してみました。

以前、AWS Step FunctionsでAmazon SES v2メール送信を試したことがあります。

https://dev.classmethod.jp/articles/aws-step-functions-ses-v2-jsonata-email/

その際、メール送信先が存在しない場合でも、以下の通りSES APIのSendEmail自体は成功します。

cm-hirai-screenshot 2025-06-10 15.07.47

そのため、実際にバウンスが発生した際に管理者が気づかない可能性があります。

バウンス発生を放置すると送信者レピュテーションが悪化し、AWSによる送信停止措置を招く可能性があるため、迅速な対応が必要です。

今回は、バウンスイベントをEventBridgeに送信し、AWS Step Functions経由でAmazon SNSでバウンス発生のメール通知を行う仕組みを構築しました。

EventBridgeから直接SNSに送信することも可能ですが、条件分岐による文言の切り替え(PermanentバウンスとTransientバウンスで異なる対応指示など)や、設定セットごとにメール通知先をDynamoDBと連携して変えるなど、将来的な拡張性を考慮してStep Functionsを挟んでいます。

構成は以下のとおりです。

cm-hirai-screenshot 2025-07-25 8.42.20
SNSトピックは作成済みとします。

SESセットアップ

Amazon SESは初期状態ではサンドボックス環境となっており、認証済みのメールアドレスに対してのみメール送信が可能などの制限があります。今回は、サンドボックス環境を解除して進めます。

サンドボックス環境の解除方法については、AWSドキュメントを参考にしてください。

https://docs.aws.amazon.com/ja_jp/ses/latest/dg/request-production-access.html

今回は、ドメインが設定済みであることを前提として、以下の設定でIDを作成しました。

  • IDタイプはドメイン
  • DKIMの有効化
  • カスタム MAIL FROM ドメインの設定

cm-hirai-screenshot 2025-06-03 8.40.23

SES設定セットの作成

設定セット名を入力し、他はデフォルトで設定セットを作成します。

cm-hirai-screenshot 2025-06-26 8.31.41

作成した設定セットに、以下の設定でイベント送信先を追加します。

  • イベントタイプ:ハードバウンス
  • 送信先オプション:Amazon EventBridge
    cm-hirai-screenshot 2025-06-26 8.32.20
    cm-hirai-screenshot 2025-06-26 8.33.23

ステートマシン作成

バウンスイベントを受信してSNS通知を行うステートマシンを作成します。

以下のコードでステートマシンを作成します。TopicArnは、作成済みのSNSトピックのARNを設定してください。

{
  "Comment": "Process SES bounce events and notify via SNS",
  "QueryLanguage": "JSONata",
  "StartAt": "ProcessBounceEvent",
  "States": {
    "ProcessBounceEvent": {
      "Type": "Pass",
      "Output": {
        "subject": "{% 'SES配信エラー通知' %}",
        "message": "{% 'SES配信エラーが発生しました\\n\\n' & 'バウンス詳細:\\n' & '- バウンスタイプ: ' & $states.input.detail.bounce.bounceType & '\\n' & '- サブタイプ: ' & $states.input.detail.bounce.bounceSubType & '\\n' & '- ステータスコード: ' & $states.input.detail.bounce.bouncedRecipients[0].status & '\\n' & '- エラーメッセージ: ' & $states.input.detail.bounce.bouncedRecipients[0].diagnosticCode & '\\n\\n' & 'メール情報:\\n' & '- 送信者: ' & $states.input.detail.mail.source & '\\n' & '- 受信者: ' & $states.input.detail.bounce.bouncedRecipients[0].emailAddress & '\\n' & '- 件名: ' & $states.input.detail.mail.commonHeaders.subject & '\\n' & '- 設定セット: ' & $split($states.input.resources[0], \"/\")[-1] & '\\n' & '- 発生時刻: ' & $states.input.detail.bounce.timestamp & '\\n\\n' & '対応が必要な場合:\\n' & '• Permanentバウンス: メールアドレスを直ちにメーリングリストから削除してください。存在しないアドレスや無効なアドレスへの継続送信は送信者レピュテーションを悪化させ、AWSによる送信停止措置を招く可能性があります\\n' & '•  Transientバウンス: 一時的な問題(メールボックス満杯など)のため、問題解決後は再送可能です\\n\\n' & '詳細情報: https://docs.aws.amazon.com/ses/latest/dg/notification-contents.html' %}"
      },
      "Next": "NotifyViaSNS"
    },
    "NotifyViaSNS": {
      "Type": "Task",
      "Resource": "arn:aws:states:::sns:publish",
      "Arguments": {
        "TopicArn": "トピックARN",
        "Subject": "{% $states.input.subject %}",
        "Message": "{% $states.input.message %}"
      },
      "End": true
    }
  }
}

cm-hirai-screenshot 2025-06-26 8.35.11

このステートマシンでは、バウンスイベントの詳細情報を元に通知メールを作成し、SNSトピックに送信します。

通知メールの文面は以下の通りです。

SES配信エラーが発生しました

バウンス詳細:
- バウンスタイプ: (bounceType)
- サブタイプ: (bounceSubType)
- ステータスコード: (status)
- エラーメッセージ: (diagnosticCode)

メール情報:
- 送信者: (source)
- 受信者: (emailAddress)
- 件名: (subject)
- 設定セット: (configuration-set名)
- 発生時刻: (timestamp)

対応が必要な場合:
• Permanentバウンス: メールアドレスを直ちにメーリングリストから削除してください。存在しないアドレスや無効なアドレスへの継続送信は送信者レピュテーションを悪化させ、AWSによる送信停止措置を招く可能性があります
• Transientバウンス: 一時的な問題(メールボックス満杯など)のため、問題解決後は再送可能です

詳細情報: https://docs.aws.amazon.com/ses/latest/dg/notification-contents.html

ステートマシン作成時、IAMロールも自動作成されます。

cm-hirai-screenshot 2025-06-26 8.35.56

EventBridgeルール作成

以下のイベントパターンで設定します。なお、設定セットでフィルタリングすることも可能です。

{
  "detail-type": ["Email Bounced"],
  "source": ["aws.ses"]
}

ターゲットに作成したステートマシンを指定し、ルールを作成します。

試してみる

構築した仕組みが正常に動作するか確認してみます。

SESのマネジメントコンソールから、バウンスシナリオを使ってテストメール送信を行います。

sxvcud6pokqkal0sb7tv

テストメール送信後、以下の通り通知メールを受信できました。

cm-hirai-screenshot 2025-07-25 8.24.09

このとき、EventBridgeからStep Functionsに渡されたイベントデータは以下の通りです。このイベントデータから、バウンスタイプや受信者情報などを抽出して通知メールを作成しています。

{
  "version": "0",
  "id": "d0a48020-393e-09b7-6d2a-eff163a56637",
  "detail-type": "Email Bounced",
  "source": "aws.ses",
  "account": "アカウントID",
  "time": "2025-06-25T23:27:38Z",
  "region": "ap-northeast-1",
  "replay-name": "test",
  "resources": [
    "arn:aws:ses:ap-northeast-1:アカウントID:configuration-set/ses-bounce-configuration-set"
  ],
  "detail": {
    "eventType": "Bounce",
    "bounce": {
      "feedbackId": "01060197a96b1d98-4817ed4b-8665-4fc9-b61d-8651533d52e8-000000",
      "bounceType": "Permanent",
      "bounceSubType": "General",
      "bouncedRecipients": [
        {
          "emailAddress": "bounce@simulator.amazonses.com",
          "action": "failed",
          "status": "5.1.1",
          "diagnosticCode": "smtp; 550 5.1.1 As requested: user unknown <bounce@simulator.amazonses.com>"
        }
      ],
      "timestamp": "2025-06-25T23:27:38.872Z",
      "remoteMtaIp": "xx.xx.xx.xx",
      "reportingMTA": "dns; e234-8.smtp-out.ap-northeast-1.amazonses.com"
    },
    "mail": {
      "timestamp": "2025-06-25T23:27:38.321Z",
      "source": "t@example.com",
      "sourceArn": "arn:aws:ses:ap-northeast-1:アカウントID:identity/example.com",
      "sendingAccountId": "アカウントID",
      "messageId": "01060197a96b1b51-808edcd8-3a53-47dc-be1c-e1df324de214-000000",
      "destination": ["bounce@simulator.amazonses.com"],
      "headersTruncated": false,
      "headers": [
        { "name": "From", "value": "t@example.com" },
        { "name": "To", "value": "bounce@simulator.amazonses.com" },
        { "name": "Subject", "value": "テスト" },
        { "name": "MIME-Version", "value": "1.0" },
        {
          "name": "Content-Type",
          "value": "multipart/alternative;  boundary=\"----=_Part_265009_1796295084.1750894058321\""
        }
      ],
      "commonHeaders": {
        "from": ["t@example.com"],
        "to": ["bounce@simulator.amazonses.com"],
        "messageId": "01060197a96b1b51-808edcd8-3a53-47dc-be1c-e1df324de214-000000",
        "subject": "テスト"
      },
      "tags": {
        "ses:source-tls-version": ["TLSv1.3"],
        "ses:operation": ["SendEmail"],
        "ses:configuration-set": ["ses-bounce-configuration-set"],
        "ses:source-ip": ["xx.xx.xx.xx"],
        "ses:from-domain": ["example.com"],
        "ses:caller-identity": ["cm-hirai.yuji"]
      }
    }
  }
}

実際の運用での利用方法

今回構築した仕組みを実際のメール送信で利用する場合、Step FunctionsやAPIからのメール送信時に設定セットを指定する必要があります。

例えば、以前の記事で紹介したStep FunctionsでのSES v2メール送信では、以下のように「ConfigurationSetName」を引数に追加します。

引数
{
  "ConfigurationSetName": "ses-bounce-configuration-set",
  "FromEmailAddress": "example@example.com",

cm-hirai-screenshot 2025-06-26 8.39.31

これにより、メール送信でバウンスが発生した場合、今回構築した仕組みによって自動的に通知メールが送信されるようになります。

最後に

Amazon SESでメール送信を行う際のバウンス通知の仕組みを、EventBridgeとStep Functions、SNSを組み合わせて構築しました。

この仕組みにより、バウンス発生時に管理者が迅速に気づくことができ、送信者レピュテーションの悪化を防ぐことが可能になります。特に、Permanentバウンスが発生した場合は、該当メールアドレスを送信リストから削除するなどの対応を早急に行うことが重要です。

なお、今回のメール文面であれば、EventBridgeから直接SNSに送信することも可能です。
ただし、条件分岐による文言の切り替え(PermanentバウンスとTransientバウンスで異なる対応指示など)や、設定セットごとにメール通知先をDynamoDBと連携して変えるなど、より高度な機能を実装しようとするとStep FunctionsやLambdaが必要になるため、拡張性を考慮してStep Functionsを挟んでいます。

メール送信を本格的に運用する際は、バウンス通知の仕組みを導入することを強く推奨します。

参考

https://docs.aws.amazon.com/ja_jp/ses/latest/dg/monitor-sending-using-event-publishing-setup.html

この記事をシェアする

facebookのロゴhatenaのロゴtwitterのロゴ

© Classmethod, Inc. All rights reserved.