Amazon SES のメール送信元をつきとめる

謎を産まない仕組みが大事
2021.11.21

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

哈喽大家好、元コンサルティング部の西野です。

先日、とあるシステムで利用している SES のリージョンを us-east-1 (バージニア北部) から ap-northeast-1 (東京) に切り替えました。
利用リージョンの指定は ECS タスク定義の環境変数で行っており、この環境変数をすべて書き換えることによって us-east-1 を利用するクライアントは存在しなくなる見込みでした。

しかし、環境変数を書き換えた翌日以降 CloudWatch のメトリクスを見てみると……。

ご覧の通り、依然として us-east-1 が利用されていることがわかります。

本稿ではこの 謎の送信元 をつきとめる方法のひとつを紹介します。

最初に結論

SES のデフォルト設定セット (default configuration sets) を使用し、E メール送信イベントを確認しましょう。
E メール送信イベントからは送信元のIP・検証済み ID・送信先 E メールアドレスなどの情報を取得できます。

CloudTrail ではわからない

「送信元がわからない?そんなの CloudTrail 見れば一発でしょ」

そんなふうに考えていた時期が俺にもありました。

CloudTrail によって記録されるのは SES の 管理イベント のみであり、E メール送信などのアクションが含まれる データイベント は記録されません1
したがって、CloudTrail のみでは今回の問題を解決できなそうです。

Amazon SES のイベント発行

そこで、SES の E メール送信イベント発行 (event publishing) を使用します。 このイベント発行は E メール送信に関するメトリクスを発行してくれる機能です。
Kinesis Data Firehose や SNS をイベント発行先とした場合、発行されたイベント (JSON レコード) から E メールの送信元を特定できます。

謎の送信元をつきとめる

それでは、それぞれの要素を具体的な作業とともに見ていきましょう。 下記の流れで進めていきます。

  1. 設定セット (configuration set) の作成
  2. イベント送信先 (event destination)の設定
  3. デフォルト設定セットの指定

最終的にこの画像のような(「謎はすべてとけた!」)状態になれば OK です。

設定セットの作成

Amazon SES のコンソール画面左部にある [Configuration sets] をクリックした後、[Create set] をクリックします。

お好きな Configuration set name を付与した後、[Create set] をクリックします。

設定セットの作成はこれだけで完了です。

イベント送信先の設定

前節で作成した設定セットの画面から [Event destinations] タブをクリックした後、[Add destionation]をクリックしイベント送信先の指定を開始します。

Select event types は発行するイベントのタイプを選択する画面です。
今回は [Sends] のみにチェックを入れ、[Next] をクリックします。

Select event types はイベントの発行先を指定する画面です。 Destination options を下記のように設定します。

  • Destination type として Amazon SNS を選択する
  • Name にお好きな名前を記入する (SNS ではなく event destination の名称です)
  • Event publishing の Enabled にチェックを入れる

SNS topic には Email アドレスをサブスクリプションとして登録してあるトピックを選択してください2。この Email アドレスに発行されたイベントが届きます。
その後、[Next] をクリックします。

設定が正しいことを確認した後、[Add destination] をクリックします。

デフォルト設定セットの指定

続いて、デフォルト設定セットの指定 (設定セットと検証済み ID の関連付け) を実施します。

検証済み ID (Verified identities) は SES のユーザーがメールを送信するときに使用するドメインもしくは Email アドレスのことを指します。 通常、設定セットを利用するためには API のパラメータもしくは E メールのヘッダーによる指定が必要ですが、検証済み ID にデフォルト設定セットを関連付けている場合この指定が不要になります。

今回のケースだと送信元が不明であるため設定セットの指定ができません。(そもそも不明なのでこの作業をしています。) したがって、このデフォルト設定セットを利用します。

また、送信元が不明である以上、どの検証済み ID から送信されたものであるか特定することも不可能です。 ですので、us-east-1 リージョンに存在する全ての検証済み ID にデフォルト設定セットを指定します

まずは us-east-1 リージョンの CloudShell から下記のコマンドを実行し検証済み ID をリストアップしましょう。

$ aws sesv2 list-email-identities --query 'EmailIdentities[].[IdentityName]' --output text
example.com
user1@example.com
user2@example.com
user3@example.com
user4@example.com
user5@example.com
user6@example.com
user7@example.com
user8@example.com
user9@example.com

続いて、これらの検証済み ID に対してデフォルト設定セットを指定していきます。

#!/bin/bash

identities=(
    "example.com"
    "user1@example.com"
    "user2@example.com"
    "user3@example.com"
    "user4@example.com"
    "user5@example.com"
    "user6@example.com"
    "user7@example.com"
    "user8@example.com"
    "user9@example.com"
)
for identity in "${identities[@]}" ; do
    aws sesv2 put-email-identity-configuration-set-attributes --email-identity ${identity} --configuration-set-name <先の手順で作成した設定セットの名称>
done

SES の設定はこれで完了です。

イベントレコードの例

SNS および SES の設定が正しく行われている場合、メールが送信されたタイミングで下記のようなイベントレコード3が配信されます。
当該イベントレコードには送信元のIP・検証済み ID・送信先 E メールアドレスなどの情報が含まれています。

{
  "eventType": "Send",
  "mail": {
    "timestamp": "2016-10-14T05:02:16.645Z",
    "source": "sender@example.com",
    "sourceArn": "arn:aws:ses:us-east-1:123456789012:identity/sender@example.com",
    "sendingAccountId": "123456789012",
    "messageId": "EXAMPLE7c191be45-e9aedb9a-02f9-4d12-a87d-dd0099a07f8a-000000",
    "destination": ["recipient@example.com"],
    "headersTruncated": false,
    "headers": [
      {
        "name": "From",
        "value": "sender@example.com"
      },
      {
        "name": "To",
        "value": "recipient@example.com"
      },
      {
        "name": "Subject",
        "value": "Message sent from Amazon SES"
      },
      {
        "name": "MIME-Version",
        "value": "1.0"
      },
      {
        "name": "Content-Type",
        "value": "multipart/mixed;  boundary=\"----=_Part_0_716996660.1476421336341\""
      },
      {
        "name": "X-SES-MESSAGE-TAGS",
        "value": "myCustomTag1=myCustomTagValue1, myCustomTag2=myCustomTagValue2"
      }
    ],
    "commonHeaders": {
      "from": ["sender@example.com"],
      "to": ["recipient@example.com"],
      "messageId": "EXAMPLE7c191be45-e9aedb9a-02f9-4d12-a87d-dd0099a07f8a-000000",
      "subject": "Message sent from Amazon SES"
    },
    "tags": {
      "ses:configuration-set": ["ConfigSet"],
      "ses:source-ip": ["192.0.2.0"],
      "ses:from-domain": ["example.com"],
      "ses:caller-identity": ["ses_user"],
      "myCustomTag1": ["myCustomTagValue1"],
      "myCustomTag2": ["myCustomTagValue2"]
    }
  },
  "send": {}
}

実際に配信されたイベントレコードから送信元 IP や検証済み ID を参照して……。

終わりに

このブログがほんの少しでも世界を良くできれば嬉しいです。
元コンサルティング部の西野 (@xiyegen) がお送りしました。