メモ > サーバ > サービス: AWS > SES メール送信ログの設定
■SES メール送信ログの設定
Amazon SESには、メール送信ログを確認する方法が提供されていない
Amazon OpenSearch Service や Amazon Elasticsearch Service に記録することはできるらしい
Amazon SES の E メール送信履歴の保存と表示
https://aws.amazon.com/jp/premiumsupport/knowledge-center/ses-email-sending-history/
Amazon SES でのメール送信ログを表示する - DENET 技術ブログ
https://blog.denet.co.jp/amazon-ses-log/
Amazon SESのメール送信ログを記録する - サーバーワークスエンジニアブログ
https://blog.serverworks.co.jp/2020/12/04/190000
Amazon OpenSearch Service は高額らしいので、S3に保存している例もある
ただしこの場合、S3に保存されたログを確認する手段を自分で用意する必要がある
SESの送信履歴を確認したい
https://zenn.dev/isseeeeey55/articles/61b350c27e1040
SES のログを S3 に出力してバウンスメールを確認してみる - Qiita
https://qiita.com/sugimount-a/items/f9202c676514dcd3d182
Kinesis Data Firehose をゼロからざっくり理解する | DevelopersIO
https://dev.classmethod.jp/articles/amazon-kinesis-data-firehose-for-beginner/
以下は発展形としていつか参考になるかも…くらい
そのメール、本当に届いてる?Amazon SESの運用で得た監視プラクティス - Cybozu Inside Out | サイボウズエンジニアのブログ
https://blog.cybozu.io/entry/2021/11/26/075846
以下を参考に、実際にS3へのログ転送を試してみる
【AWS】AWS SESのログをKinesis Data Firehose経由でS3へ転送してみました - Qiita
https://qiita.com/hyj624117615/items/6bf44f2f86c252e3e00b
s3のライフサイクルルールを設定してみる - Qiita
https://qiita.com/miyuki_samitani/items/cbea495fb116b5bf5db6
以下はS3への保存では無いが、部分的には参考になる
SESのメール送信履歴をOpenSearch Serviceで表示してみた | DevelopersIO
https://dev.classmethod.jp/articles/ses-visualisation-email-sending-history-with-opensearch-service/
【AWS】AWS SESのログをKinesis Data Firehose経由でS3へ転送してみました - Qiita
https://qiita.com/hyj624117615/items/6bf44f2f86c252e3e00b
■S3にバケットを作成
S3 → バケットを作成
バケット名: refirio-ses-log
AWSリージョン: アジアパシフィック(東京)
このバケットのブロックパブリックアクセス設定: パブリックアクセスをすべて ブロック
※「バケットのバージョニング」はデフォルトのまま(無効)とした
「デフォルトの暗号化」はデフォルトのまま(SSE-S3 / 有効にする)とした
■Kinesis Data Firehoseに配信ストリームを作成
Kinesis Data Firehose → 配信ストリームを作成
ソース: Direct PUT
送信先: Amazon S3
配信ストリーム名: refirio-ses-kinesis
S3バケット: s3://refirio-ses-log
S3バケットプレフィックス: ses-log-
S3バケットエラー出力プレフィックス: ses-log-error-
バッファ間隔: 60
※「S3バケット」は上で作成したものを選択
「バッファ間隔」は検証のために60にした。本番運用なら、300のままでいいかもしれない
※「許可」はデフォルトのまま「IAM ロール KinesisFirehoseServiceRole-refirio-ap-northeast-1-1234567890123 を作成または更新」を選択したが、
すでに作成したものがあるならそれを使えば良さそう(2回目以降に作成する場合など)
作成すると「refirio-ses-kinesis の作成中。ステータスが更新されるまでに最大5分かかる場合があります。」と表示されるので待つ
「配信ストリームを作成」ボタン押して以下のエラーが作成された場合、作業しているユーザの権限を確認する
配信ストリームは作成されませんでした
配信ストリーム refirio-ses-kinesis の作成に必要な許可がありません。IAM 許可を確認して変更し、このユーザーに必要な許可が付与されているようにしてください。
アクション: iamadmin:CreateServiceRole/CreatePolicyForServiceRole/UpdateServiceRolePolicy
ユーザー: arn:aws:sts::123456789012:assumed-role/AWSReservedSSO_PowerUserAccess_1db0a2445f639f21/refirio
APIレスポンス: User: arn:aws:sts::123456789012:assumed-role/AWSReservedSSO_PowerUserAccess_1db0a2445f639f21/refirio is not authorized to perform: iam:CreateRole on resource: arn:aws:iam::123456789012:role/service-role/KinesisFirehoseServiceRole-refirio-ap-northeast-1-1674707361061 because no identity-based policy allows the iam:CreateRole action
■SESを設定
Amazon Simple Email Service → 設定セット → セットの作成
設定セット名: refirio-ses-log
※設定セットは引き続きの設定が必要だが、このタイミングでいったんIAMポリシーとIAMロールを作成する
■IAMポリシーを作成
Identity and Access Management (IAM) → ポリシー → ポリシーの作成
「JSON」タブで以下を入力する
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "0",
"Effect": "Allow",
"Action": "firehose:ListDeliveryStreams",
"Resource": "*"
},
{
"Sid": "1",
"Effect": "Allow",
"Action": "firehose:*",
"Resource": "arn:aws:firehose:*:123456789012:deliverystream/*"
}
]
}
※「123456789012」部分にはAWSのIDを入力する
名前: ses-log-policy
これでポリシーを作成する
■IAMロールを作成
Identity and Access Management (IAM) → ロール → ロールを作成
「信頼されたエンティティタイプ」で「カスタム信頼ポリシー」を選択し、表示される「カスタム信頼ポリシー」欄に以下を入力する
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": [
"ses.amazonaws.com"
]
},
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": {
"AWS:SourceAccount": "123456789012",
"AWS:SourceArn": "arn:aws:ses:ap-northeast-1:123456789012:configuration-set/refirio-ses-log"
}
}
}
]
}
※「123456789012」部分にはAWSのIDを、「refirio-ses-log」部分には設定セット名をそれぞれ入力する
「許可を追加」で「IAMポリシーを作成」の手順で作成したポリシー(ses-log-policy)を選択
名前: ses-log-role
これでロールを作成する
■SESを設定(続き)
Amazon Simple Email Service → 設定セット → refirio-ses-log → イベント送信先 → 送信先の追加
※「refirio-ses-log」は上の手順で作成した設定セット
今回はイベントタイプの選択で
「送信」「拒否」「配信」「ハードバウンス」「苦情数」「配信の遅延」「サブスクリプション」
にチェックを入れてみる
※イベントタイプの内容を絞ることでコストを最適化できるみたい
送信先の指定は
送信先タイプ: Amazon Kinesis Data Firehose
名前: refirio-ses-log
配信ストリーム: refirio-ses-kinesis
Identity and Access Management (IAM) ロール: ses-log-role
※「配信ストリーム」は上で作成したものを選択
※「Identity and Access Management (IAM) ロール」は上で作成したものを選択
■メール送信テスト
Amazon Simple Email Service → 検証済みID → refirio.net → テストEメールの送信
Eメール形式: フォーマット済み
From-address: info@refirio.net
シナリオ: 配信の成功
件名: 送信テスト
本文: これは送信テストです。
設定セット: refirio-ses-log
※「設定セット」は上で作成したものを選択
「テストEメールの送信」ボタンをクリック(実際にメールは送信されない)
2〜3分ほど待つと、refirio-ses-log バケット内にフォルダが作成された
refirio-ses-log/ses-log-2023/01/26/06/refirio-ses-kinesis-1-2023-01-26-06-32-55-4459a487-45e3-41ad-80ca-d53999eeddc2
{"eventType":"Delivery","mail":{"timestamp":"2023-01-26T06:32:14.171Z","source":"info@refirio.net","sourceArn":"arn:aws:ses:ap-northeast-1:123456789012:identity/refirio.net","sendingAccountId":"123456789012","messageId":"01060185ecc6de5b-7376664e-c6e8-4a33-9d11-a8f8be738b5e-000000","destination":["success@simulator.amazonses.com"],"headersTruncated":false,"headers":[{"name":"From","value":"info@refirio.net"},{"name":"To","value":"success@simulator.amazonses.com"},{"name":"Subject","value":"送信テスト"},{"name":"MIME-Version","value":"1.0"},{"name":"Content-Type","value":"multipart/alternative; boundary=\"----=_Part_80348_1716894568.1674714734175\""}],"commonHeaders":{"from":["info@refirio.net"],"to":["success@simulator.amazonses.com"],"messageId":"01060185ecc6de5b-7376664e-c6e8-4a33-9d11-a8f8be738b5e-000000","subject":"送信テスト"},"tags":{"ses:operation":["SendEmail"],"ses:configuration-set":["refirio-ses-log"],"ses:source-ip":["203.0.113.1"],"ses:from-domain":["refirio.net"],"ses:caller-identity":["refirio-user"],"ses:outgoing-ip":["23.251.234.1"]}},"delivery":{"timestamp":"2023-01-26T06:32:15.224Z","processingTimeMillis":1053,"recipients":["success@simulator.amazonses.com"],"smtpResponse":"250 2.6.0 Message received","reportingMTA":"e234-1.smtp-out.ap-northeast-1.amazonses.com"}}
{"eventType":"Send","mail":{"timestamp":"2023-01-26T06:32:14.171Z","source":"info@refirio.net","sourceArn":"arn:aws:ses:ap-northeast-1:123456789012:identity/refirio.net","sendingAccountId":"123456789012","messageId":"01060185ecc6de5b-7376664e-c6e8-4a33-9d11-a8f8be738b5e-000000","destination":["success@simulator.amazonses.com"],"headersTruncated":false,"headers":[{"name":"From","value":"info@refirio.net"},{"name":"To","value":"success@simulator.amazonses.com"},{"name":"Subject","value":"送信テスト"},{"name":"MIME-Version","value":"1.0"},{"name":"Content-Type","value":"multipart/alternative; boundary=\"----=_Part_80348_1716894568.1674714734175\""}],"commonHeaders":{"from":["info@refirio.net"],"to":["success@simulator.amazonses.com"],"messageId":"01060185ecc6de5b-7376664e-c6e8-4a33-9d11-a8f8be738b5e-000000","subject":"送信テスト"},"tags":{"ses:operation":["SendEmail"],"ses:configuration-set":["refirio-ses-log"],"ses:source-ip":["203.0.113.1"],"ses:from-domain":["refirio.net"],"ses:caller-identity":["refirio-user"]}},"send":{}}
それらしいものが格納されている
再度テストEメールを送信してみる。今回はシナリオで「バウンス」を選択して送信してみる
2〜3分ほど待つと、新たにファイルが作成された
refirio-ses-log/ses-log-2023/01/26/06/refirio-ses-kinesis-1-2023-01-26-06-38-14-c5d40628-51e3-4636-88e9-681b3e08ac53
{"eventType":"Send","mail":{"timestamp":"2023-01-26T06:37:30.930Z","source":"info@refirio.net","sourceArn":"arn:aws:ses:ap-northeast-1:123456789012:identity/refirio.net","sendingAccountId":"123456789012","messageId":"01060185eccbb3b2-7b3a8bc1-aebd-4f35-b385-369eb6fd1691-000000","destination":["bounce@simulator.amazonses.com"],"headersTruncated":false,"headers":[{"name":"From","value":"info@refirio.net"},{"name":"To","value":"bounce@simulator.amazonses.com"},{"name":"Subject","value":"送信テスト(バウンス)"},{"name":"MIME-Version","value":"1.0"},{"name":"Content-Type","value":"multipart/alternative; boundary=\"----=_Part_3104396_282462092.1674715050933\""}],"commonHeaders":{"from":["info@refirio.net"],"to":["bounce@simulator.amazonses.com"],"messageId":"01060185eccbb3b2-7b3a8bc1-aebd-4f35-b385-369eb6fd1691-000000","subject":"送信テスト(バウンス)"},"tags":{"ses:operation":["SendEmail"],"ses:configuration-set":["refirio-ses-log"],"ses:source-ip":["203.0.113.1"],"ses:from-domain":["refirio.net"],"ses:caller-identity":["refirio-user"]}},"send":{}}
{"eventType":"Bounce","bounce":{"feedbackId":"01060185eccbb630-c60c6634-7090-4b79-aabc-b6e2b08d9af2-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-01-26T06:37:31.687Z","reportingMTA":"dns; e234-2.smtp-out.ap-northeast-1.amazonses.com"},"mail":{"timestamp":"2023-01-26T06:37:30.930Z","source":"info@refirio.net","sourceArn":"arn:aws:ses:ap-northeast-1:123456789012:identity/refirio.net","sendingAccountId":"123456789012","messageId":"01060185eccbb3b2-7b3a8bc1-aebd-4f35-b385-369eb6fd1691-000000","destination":["bounce@simulator.amazonses.com"],"headersTruncated":false,"headers":[{"name":"From","value":"info@refirio.net"},{"name":"To","value":"bounce@simulator.amazonses.com"},{"name":"Subject","value":"送信テスト(バウンス)"},{"name":"MIME-Version","value":"1.0"},{"name":"Content-Type","value":"multipart/alternative; boundary=\"----=_Part_3104396_282462092.1674715050933\""}],"commonHeaders":{"from":["info@refirio.net"],"to":["bounce@simulator.amazonses.com"],"messageId":"01060185eccbb3b2-7b3a8bc1-aebd-4f35-b385-369eb6fd1691-000000","subject":"送信テスト(バウンス)"},"tags":{"ses:operation":["SendEmail"],"ses:configuration-set":["refirio-ses-log"],"ses:source-ip":["203.0.113.1"],"ses:from-domain":["refirio.net"],"ses:caller-identity":["refirio-user"]}}}
「メール1送信=1ファイル」でログが作成されている
■デフォルト設定セットの割り当て
Amazon Simple Email Service → 検証済みID → refirio.net → 設定セット → 編集
デフォルト設定セットの割り当て: (チェックを入れる)
デフォルト設定セット: refirio-ses-log
※「デフォルト設定セット」は上で作成したものを選択
これでメール送信時に「設定セット」を指定しなくても、自動的に設定セットが割り当てられる
SMTPからのメール送信なども、自動的に設定セットが使用される
■古いログの自動削除
S3 → refirio-ses-log → 管理 → ライフサイクルルールを作成する
ライフサイクルルール名: refirio-ses-log-delete
ルールスコープを選択: バケット内のすべてのオブジェクトに適用
バケット内のすべてのオブジェクトに適用: (チェックを入れる)
ライフサイクルルールのアクション: オブジェクトの現行バージョンを有効期限切れにする
オブジェクト作成後の日数: 3
※アクションは「有効期限切れ=S3から削除される」ということらしい
「オブジェクト作成後の日数」は検証のために3にした。本番運用なら、90(=3ヶ月)など適宜設定する
※本当に削除されるか確認したところ、
・2023/01/26 03:30 のファイル(12:30 のファイル)で確認
・2023/01/30 時点で削除されずに残っていた
・2023/01/31 時点で削除されていた
となっていた。ピッタリ3日では無いようだが、自動的に削除されていることは確認できた
■Postfix経由での送信
「SES PostfixからSMTPでメールを送信」の手順をもとに、Postfixを経由してSESからメール送信できるようにする
また、外部からPostfixのアカウントを経由してSESからメール送信できるようにもする
この状態で送信テストし、どのようにログが記録されるか確認
外部のPHPからSMTPを直接叩いてメール送信した場合、S3には以下のログが記録された
{"eventType":"Delivery","mail":{"timestamp":"2023-01-27T02:36:17.921Z","source":"info@refirio.net","sourceArn":"arn:aws:ses:ap-northeast-1:123456789012:identity/refirio.net","sendingAccountId":"123456789012","messageId":"01060185f1153881-050e347e-1c63-4627-a941-b146682babf0-000000","destination":["example@gmail.com"],"headersTruncated":false,"headers":[{"name":"Received","value":"from localhost (example.com [203.0.113.1]) by email-smtp.amazonaws.com with SMTP (SimpleEmailService-d-EQ3QJVK0M) id MAvuw8Xe28pKGsVJ1b6I for example@gmail.com; Fri, 27 Jan 2023 02:36:17 +0000 (UTC)"},{"name":"Date","value":"Fri, 27 Jan 2023 11:36:17 +0900"},{"name":"To","value":"メール受信者 <example@gmail.com>"},{"name":"From","value":"メール送信者 <info@refirio.net>"},{"name":"Subject","value":"外部SMTPからの送信テスト"},{"name":"Message-ID","value":"<0b123d8412043e673ccc717b26354311@localhost>"},{"name":"X-Mailer","value":"PHPMailer 5.2.19 (https://github.com/PHPMailer/PHPMailer)"},{"name":"MIME-Version","value":"1.0"},{"name":"Content-Type","value":"text/plain; charset=UTF-8"},{"name":"Content-Transfer-Encoding","value":"base64"}],"commonHeaders":{"from":["\"メール送信者\" <info@refirio.net>"],"date":"Fri, 27 Jan 2023 11:36:17 +0900","to":["\"メール受信者\" <example@gmail.com>"],"messageId":"01060185f1153881-050e347e-1c63-4627-a941-b146682babf0-000000","subject":"外部SMTPからの送信テスト"},"tags":{"ses:operation":["SendSmtpEmail"],"ses:configuration-set":["refirio-ses-log"],"ses:source-ip":["203.0.113.1"],"ses:from-domain":["refirio.net"],"ses:caller-identity":["cre-test-smtp-user.20220726"],"ses:outgoing-ip":["23.251.234.3"]}},"delivery":{"timestamp":"2023-01-27T02:36:19.434Z","processingTimeMillis":1513,"recipients":["example@gmail.com"],"smtpResponse":"250 2.0.0 OK 1674786979 m3-20020a17090a730300b002297f945cf0si3008883pjk.57 - gsmtp","reportingMTA":"e234-3.smtp-out.ap-northeast-1.amazonses.com"}}
{"eventType":"Send","mail":{"timestamp":"2023-01-27T02:36:17.921Z","source":"info@refirio.net","sourceArn":"arn:aws:ses:ap-northeast-1:123456789012:identity/refirio.net","sendingAccountId":"123456789012","messageId":"01060185f1153881-050e347e-1c63-4627-a941-b146682babf0-000000","destination":["example@gmail.com"],"headersTruncated":false,"headers":[{"name":"Received","value":"from localhost (example.com [203.0.113.1]) by email-smtp.amazonaws.com with SMTP (SimpleEmailService-d-EQ3QJVK0M) id MAvuw8Xe28pKGsVJ1b6I for example@gmail.com; Fri, 27 Jan 2023 02:36:17 +0000 (UTC)"},{"name":"Date","value":"Fri, 27 Jan 2023 11:36:17 +0900"},{"name":"To","value":"メール受信者 <example@gmail.com>"},{"name":"From","value":"メール送信者 <info@refirio.net>"},{"name":"Subject","value":"外部SMTPからの送信テスト"},{"name":"Message-ID","value":"<0b123d8412043e673ccc717b26354311@localhost>"},{"name":"X-Mailer","value":"PHPMailer 5.2.19 (https://github.com/PHPMailer/PHPMailer)"},{"name":"MIME-Version","value":"1.0"},{"name":"Content-Type","value":"text/plain; charset=UTF-8"},{"name":"Content-Transfer-Encoding","value":"base64"}],"commonHeaders":{"from":["\"メール送信者\" <info@refirio.net>"],"date":"Fri, 27 Jan 2023 11:36:17 +0900","to":["\"メール受信者\" <example@gmail.com>"],"messageId":"01060185f1153881-050e347e-1c63-4627-a941-b146682babf0-000000","subject":"外部SMTPからの送信テスト"},"tags":{"ses:operation":["SendSmtpEmail"],"ses:configuration-set":["refirio-ses-log"],"ses:source-ip":["203.0.113.1"],"ses:from-domain":["refirio.net"],"ses:caller-identity":["cre-test-smtp-user.20220726"]}},"send":{}}
EC2を経由していないので、EC2の /var/log/maillog には何も記録されていない
外部のPHPからEC2経由でメール送信した場合、S3には以下のログが記録された
{"eventType":"Delivery","mail":{"timestamp":"2023-01-27T02:36:51.061Z","source":"info@refirio.net","sourceArn":"arn:aws:ses:ap-northeast-1:123456789012:identity/refirio.net","sendingAccountId":"123456789012","messageId":"01060185f115b9f5-0a7e240a-54ef-49e9-9725-b77a002bd950-000000","destination":["example@gmail.com"],"headersTruncated":false,"headers":[{"name":"Received","value":"from refirio.net (ec2-3-113-235-47.ap-northeast-1.compute.amazonaws.com [3.113.235.47]) by email-smtp.amazonaws.com with SMTP (SimpleEmailService-d-1B60FHL0M) id BqzsiwDa4Rkwhg0fCpCS for example@gmail.com; Fri, 27 Jan 2023 02:36:51 +0000 (UTC)"},{"name":"Received","value":"from localhost (example.com [203.0.113.1]) by refirio.net (Postfix) with ESMTPA id BAF64CAF15C for <example@gmail.com>; Fri, 27 Jan 2023 11:36:50 +0900 (JST)"},{"name":"Date","value":"Fri, 27 Jan 2023 11:36:50 +0900"},{"name":"To","value":"メール受信者 <example@gmail.com>"},{"name":"From","value":"メール送信者 <info@refirio.net>"},{"name":"Subject","value":"外部SMTPからの送信テスト2"},{"name":"Message-ID","value":"<5e0f33a5a5e0e2bed18ad4a102047b1e@localhost>"},{"name":"X-Mailer","value":"PHPMailer 5.2.19 (https://github.com/PHPMailer/PHPMailer)"},{"name":"MIME-Version","value":"1.0"},{"name":"Content-Type","value":"text/plain; charset=UTF-8"},{"name":"Content-Transfer-Encoding","value":"base64"}],"commonHeaders":{"from":["\"メール送信者\" <info@refirio.net>"],"date":"Fri, 27 Jan 2023 11:36:50 +0900","to":["\"メール受信者\" <example@gmail.com>"],"messageId":"01060185f115b9f5-0a7e240a-54ef-49e9-9725-b77a002bd950-000000","subject":"外部SMTPからの送信テスト2"},"tags":{"ses:operation":["SendSmtpEmail"],"ses:configuration-set":["refirio-ses-log"],"ses:source-ip":["3.113.235.47"],"ses:from-domain":["refirio.net"],"ses:caller-identity":["cre-test-smtp-user.20220726"],"ses:outgoing-ip":["23.251.234.5"]}},"delivery":{"timestamp":"2023-01-27T02:36:52.514Z","processingTimeMillis":1453,"recipients":["example@gmail.com"],"smtpResponse":"250 2.0.0 OK 1674787012 12-20020a17090a034c00b002264d5dfc15si6926883pjf.113 - gsmtp","reportingMTA":"e234-5.smtp-out.ap-northeast-1.amazonses.com"}}
{"eventType":"Send","mail":{"timestamp":"2023-01-27T02:36:51.061Z","source":"info@refirio.net","sourceArn":"arn:aws:ses:ap-northeast-1:123456789012:identity/refirio.net","sendingAccountId":"123456789012","messageId":"01060185f115b9f5-0a7e240a-54ef-49e9-9725-b77a002bd950-000000","destination":["example@gmail.com"],"headersTruncated":false,"headers":[{"name":"Received","value":"from refirio.net (ec2-3-113-235-47.ap-northeast-1.compute.amazonaws.com [3.113.235.47]) by email-smtp.amazonaws.com with SMTP (SimpleEmailService-d-1B60FHL0M) id BqzsiwDa4Rkwhg0fCpCS for example@gmail.com; Fri, 27 Jan 2023 02:36:51 +0000 (UTC)"},{"name":"Received","value":"from localhost (example.com [203.0.113.1]) by refirio.net (Postfix) with ESMTPA id BAF64CAF15C for <example@gmail.com>; Fri, 27 Jan 2023 11:36:50 +0900 (JST)"},{"name":"Date","value":"Fri, 27 Jan 2023 11:36:50 +0900"},{"name":"To","value":"メール受信者 <example@gmail.com>"},{"name":"From","value":"メール送信者 <info@refirio.net>"},{"name":"Subject","value":"外部SMTPからの送信テスト2"},{"name":"Message-ID","value":"<5e0f33a5a5e0e2bed18ad4a102047b1e@localhost>"},{"name":"X-Mailer","value":"PHPMailer 5.2.19 (https://github.com/PHPMailer/PHPMailer)"},{"name":"MIME-Version","value":"1.0"},{"name":"Content-Type","value":"text/plain; charset=UTF-8"},{"name":"Content-Transfer-Encoding","value":"base64"}],"commonHeaders":{"from":["\"メール送信者\" <info@refirio.net>"],"date":"Fri, 27 Jan 2023 11:36:50 +0900","to":["\"メール受信者\" <example@gmail.com>"],"messageId":"01060185f115b9f5-0a7e240a-54ef-49e9-9725-b77a002bd950-000000","subject":"外部SMTPからの送信テスト2"},"tags":{"ses:operation":["SendSmtpEmail"],"ses:configuration-set":["refirio-ses-log"],"ses:source-ip":["3.113.235.47"],"ses:from-domain":["refirio.net"],"ses:caller-identity":["cre-test-smtp-user.20220726"]}},"send":{}}
EC2の /var/log/maillog には以下のとおり送信成功が記録されている
Jan 27 11:36:50 ip-10-1-0-47 postfix/smtpd[3863]: connect from example.com[203.0.113.1]
Jan 27 11:36:50 ip-10-1-0-47 postfix/smtpd[3863]: BAF64CAF15C: client=example.com[203.0.113.1], sasl_method=LOGIN, sasl_username=info@refirio.net
Jan 27 11:36:50 ip-10-1-0-47 postfix/cleanup[3867]: BAF64CAF15C: message-id=<5e0f33a5a5e0e2bed18ad4a102047b1e@localhost>
Jan 27 11:36:50 ip-10-1-0-47 postfix/qmgr[3857]: BAF64CAF15C: from=<info@refirio.net>, size=795, nrcpt=1 (queue active)
Jan 27 11:36:50 ip-10-1-0-47 postfix/smtpd[3863]: disconnect from example.com[203.0.113.1]
Jan 27 11:36:50 ip-10-1-0-47 postfix/smtp[3868]: Trusted TLS connection established to email-smtp.ap-northeast-1.amazonaws.com[203.0.113.2]:587: TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)
Jan 27 11:36:51 ip-10-1-0-47 postfix/smtp[3868]: BAF64CAF15C: to=<example@gmail.com>, relay=email-smtp.ap-northeast-1.amazonaws.com[203.0.113.2]:587, delay=0.52, delays=0.11/0.02/0.14/0.25, dsn=2.0.0, status=sent (250 Ok 01060185f115b9f5-0a7e240a-54ef-49e9-9725-b77a002bd950-000000)
Jan 27 11:36:51 ip-10-1-0-47 postfix/qmgr[3857]: BAF64CAF15C: removed
存在しないメールアドレスに対して、外部のPHPからEC2経由でメール送信した場合、S3には以下のログが記録された
{"eventType":"Bounce","bounce":{"feedbackId":"01060185f11ae6a9-8857de58-a91b-4e05-95d0-91f01b7e91c6-000000","bounceType":"Permanent","bounceSubType":"General","bouncedRecipients":[{"emailAddress":"abcdxxx@refirio.net","action":"failed","status":"5.1.1","diagnosticCode":"smtp; 550 5.1.1 <abcdxxx@refirio.net>: Recipient address rejected: User unknown in relay recipient table"}],"timestamp":"2023-01-27T02:42:30.322Z","reportingMTA":"dns; e234-2.smtp-out.ap-northeast-1.amazonses.com"},"mail":{"timestamp":"2023-01-27T02:42:29.554Z","source":"info@refirio.net","sourceArn":"arn:aws:ses:ap-northeast-1:123456789012:identity/refirio.net","sendingAccountId":"123456789012","messageId":"01060185f11ae432-60aab4e8-b3a4-4f40-9b8b-886d027b3c50-000000","destination":["abcdxxx@refirio.net"],"headersTruncated":false,"headers":[{"name":"Received","value":"from refirio.net (ec2-3-113-235-47.ap-northeast-1.compute.amazonaws.com [3.113.235.47]) by email-smtp.amazonaws.com with SMTP (SimpleEmailService-d-XLR0CNL0M) id jWkq9bUZroC04PmhwDve for abcdxxx@refirio.net; Fri, 27 Jan 2023 02:42:29 +0000 (UTC)"},{"name":"Received","value":"from localhost (example.com [203.0.113.1]) by refirio.net (Postfix) with ESMTPA id 47471CAF15C for <abcdxxx@refirio.net>; Fri, 27 Jan 2023 11:42:29 +0900 (JST)"},{"name":"Date","value":"Fri, 27 Jan 2023 11:42:29 +0900"},{"name":"To","value":"メール受信者 <abcdxxx@refirio.net>"},{"name":"From","value":"メール送信者 <info@refirio.net>"},{"name":"Subject","value":"外部SMTPからのバウンスメールテスト"},{"name":"Message-ID","value":"<44c8337f6dbf9e4d37ce2fb7eedc0a41@localhost>"},{"name":"X-Mailer","value":"PHPMailer 5.2.19 (https://github.com/PHPMailer/PHPMailer)"},{"name":"MIME-Version","value":"1.0"},{"name":"Content-Type","value":"text/plain; charset=UTF-8"},{"name":"Content-Transfer-Encoding","value":"base64"}],"commonHeaders":{"from":["\"メール送信者\" <info@refirio.net>"],"date":"Fri, 27 Jan 2023 11:42:29 +0900","to":["\"メール受信者\" <abcdxxx@refirio.net>"],"messageId":"01060185f11ae432-60aab4e8-b3a4-4f40-9b8b-886d027b3c50-000000","subject":"外部SMTPからのバウンスメールテスト"},"tags":{"ses:operation":["SendSmtpEmail"],"ses:configuration-set":["refirio-ses-log"],"ses:source-ip":["3.113.235.47"],"ses:from-domain":["refirio.net"],"ses:caller-identity":["cre-test-smtp-user.20220726"]}}}
{"eventType":"Send","mail":{"timestamp":"2023-01-27T02:42:29.554Z","source":"info@refirio.net","sourceArn":"arn:aws:ses:ap-northeast-1:123456789012:identity/refirio.net","sendingAccountId":"123456789012","messageId":"01060185f11ae432-60aab4e8-b3a4-4f40-9b8b-886d027b3c50-000000","destination":["abcdxxx@refirio.net"],"headersTruncated":false,"headers":[{"name":"Received","value":"from refirio.net (ec2-3-113-235-47.ap-northeast-1.compute.amazonaws.com [3.113.235.47]) by email-smtp.amazonaws.com with SMTP (SimpleEmailService-d-XLR0CNL0M) id jWkq9bUZroC04PmhwDve for abcdxxx@refirio.net; Fri, 27 Jan 2023 02:42:29 +0000 (UTC)"},{"name":"Received","value":"from localhost (example.com [203.0.113.1]) by refirio.net (Postfix) with ESMTPA id 47471CAF15C for <abcdxxx@refirio.net>; Fri, 27 Jan 2023 11:42:29 +0900 (JST)"},{"name":"Date","value":"Fri, 27 Jan 2023 11:42:29 +0900"},{"name":"To","value":"メール受信者 <abcdxxx@refirio.net>"},{"name":"From","value":"メール送信者 <info@refirio.net>"},{"name":"Subject","value":"外部SMTPからのバウンスメールテスト"},{"name":"Message-ID","value":"<44c8337f6dbf9e4d37ce2fb7eedc0a41@localhost>"},{"name":"X-Mailer","value":"PHPMailer 5.2.19 (https://github.com/PHPMailer/PHPMailer)"},{"name":"MIME-Version","value":"1.0"},{"name":"Content-Type","value":"text/plain; charset=UTF-8"},{"name":"Content-Transfer-Encoding","value":"base64"}],"commonHeaders":{"from":["\"メール送信者\" <info@refirio.net>"],"date":"Fri, 27 Jan 2023 11:42:29 +0900","to":["\"メール受信者\" <abcdxxx@refirio.net>"],"messageId":"01060185f11ae432-60aab4e8-b3a4-4f40-9b8b-886d027b3c50-000000","subject":"外部SMTPからのバウンスメールテスト"},"tags":{"ses:operation":["SendSmtpEmail"],"ses:configuration-set":["refirio-ses-log"],"ses:source-ip":["3.113.235.47"],"ses:from-domain":["refirio.net"],"ses:caller-identity":["cre-test-smtp-user.20220726"]}},"send":{}}
EC2の /var/log/maillog には以下のとおり送信成功が記録されている
SESへのリレー自体は成功しているから…だと思われる
つまり送信ログからエラーを検知したければ、/var/log/maillog ではなくS3の方を調べる必要がある
Jan 27 11:42:29 ip-10-1-0-47 postfix/smtpd[3884]: connect from example.com[203.0.113.1]
Jan 27 11:42:29 ip-10-1-0-47 postfix/smtpd[3884]: 47471CAF15C: client=example.com[203.0.113.1], sasl_method=LOGIN, sasl_username=info@refirio.net
Jan 27 11:42:29 ip-10-1-0-47 postfix/cleanup[3888]: 47471CAF15C: message-id=<44c8337f6dbf9e4d37ce2fb7eedc0a41@localhost>
Jan 27 11:42:29 ip-10-1-0-47 postfix/qmgr[3857]: 47471CAF15C: from=<info@refirio.net>, size=846, nrcpt=1 (queue active)
Jan 27 11:42:29 ip-10-1-0-47 postfix/smtpd[3884]: disconnect from example.com[203.0.113.1]
Jan 27 11:42:29 ip-10-1-0-47 postfix/smtp[3889]: Trusted TLS connection established to email-smtp.ap-northeast-1.amazonaws.com[203.0.113.2]:587: TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)
Jan 27 11:42:29 ip-10-1-0-47 postfix/smtp[3889]: 47471CAF15C: to=<abcdxxx@refirio.net>, relay=email-smtp.ap-northeast-1.amazonaws.com[203.0.113.2]:587, delay=0.52, delays=0.12/0.01/0.13/0.27, dsn=2.0.0, status=sent (250 Ok 01060185f11ae432-60aab4e8-b3a4-4f40-9b8b-886d027b3c50-000000)
Jan 27 11:42:29 ip-10-1-0-47 postfix/qmgr[3857]: 47471CAF15C: removed
なお、S3に格納される際のファイル名は、先に記載したとおり refirio-ses-log/ses-log-2023/01/26/06/refirio-ses-kinesis-1-2023-01-26-06-32-55-4459a487-45e3-41ad-80ca-d53999eeddc2 のような場所と名前になる
日付や時間が含まれているが、これはUTCの日時となっている(テストメールでなければ、ファイル内に日本時間が記録される)
特定の日付のメールを丸ごと取得するような場合、時差を考慮してデータを取得する必要があるので注意
■プログラムからのメール送信ログ確認
一例だが、以下のようなPHPプログラムでログを表示できる
SDKの導入については「AWS SDK(バージョン3)」を参照
<?php
require 'vendor/autoload.php';
use Aws\S3\S3Client;
use Aws\S3\Exception\S3Exception;
define('AWS_KEY', 'XXXXX');
define('AWS_SECRET', 'YYYYY');
define('AWS_REGION', 'ap-northeast-1');
define('AWS_S3_BUCKET', 'refirio-ses-log');
define('AWS_S3_SES_PREFIX', 'ses-log-');
define('AWS_S3_SES_DATE', '2023/01/27');
$logs = [];
try {
// アクセスキーとシークレットアクセスキーを指定して接続
$client = new S3Client([
'credentials' => [
'key' => AWS_KEY,
'secret' => AWS_SECRET,
],
'region' => AWS_REGION,
'version' => 'latest',
]);
// ディレクトリの一覧を取得
$result = $client->listObjects([
'Bucket' => AWS_S3_BUCKET,
'Prefix' => AWS_S3_SES_PREFIX . AWS_S3_SES_DATE . '/',
'Delimiter' => '/',
]);
$directories = [];
foreach ($result['CommonPrefixes'] as $prefix) {
$directories[] = $prefix['Prefix'];
}
// ファイルの一覧を取得
$files = [];
foreach ($directories as $directory) {
$result = $client->listObjects([
'Bucket' => AWS_S3_BUCKET,
'Prefix' => $directory,
'Delimiter' => '/',
]);
foreach ($result['Contents'] as $content) {
$files[] = $content['Key'];
}
}
// ログの内容を取得
foreach ($files as $file) {
$result = $client->getObject([
'Bucket' => AWS_S3_BUCKET,
'Key' => $file,
]);
$lines = explode("\n", $result['Body']);
foreach ($lines as $line) {
if (empty($line)) {
continue;
}
$logs[] = json_decode($line, true);
}
}
} catch (S3Exception $e) {
exit('S3Exception: ' . $e->getMessage());
} catch (Exception $e) {
exit('Exception: ' . $e->getMessage());
}
echo "<table border=\"1\">\n";
echo "<tr>\n";
echo "<th>eventType</td>\n";
echo "<th>timestamp</td>\n";
echo "<th>messageId</td>\n";
echo "<th>source</td>\n";
echo "<th>destination</td>\n";
echo "<th>headers From</td>\n";
echo "<th>headers To</td>\n";
echo "<th>headers Subject</td>\n";
echo "</tr>\n";
foreach ($logs as $data) {
if ($data['eventType'] == 'Send') {
continue;
}
$headers = [];
foreach ($data['mail']['headers'] as $header) {
$headers[$header['name']] = $header['value'];
}
echo "<tr>\n";
echo "<td>" . $data['eventType'] . "</td>\n";
echo "<td>" . date('Y-m-d H:i:s', strtotime($data['mail']['timestamp'])) . "</td>\n";
echo "<td>" . $data['mail']['messageId'] . "</td>\n";
echo "<td>" . $data['mail']['source'] . "</td>\n";
echo "<td>" . implode(', ', $data['mail']['destination']) . "</td>\n";
echo "<td>" . $headers['From'] . "</td>\n";
echo "<td>" . $headers['To'] . "</td>\n";
echo "<td>" . $headers['Subject'] . "</td>\n";
echo "</tr>\n";
}
echo "</table>\n";
■バウンスメールの設定
別途バウンスメールの設定をしておくといい
メールログからバウンスメールが発生したことを確認できたとしても、バウンスメールほどの情報量が無い
詳細は、このファイル内の「SES メール送信 > バウンスメールの設定」を参照
■引き続き
ログファイル名、ログファイルの内容とも9時間の時差がある(1月26日19時に送ったものが1月26日10時として記録された)
調整できるか