はじめに
SESのバウンス率が上昇すると、AWSから警告メールが送られてきます。
放置したままにすると、SES
の機能が利用停止になるので気を付けましょう。
恥ずかしながら警告メールを受け取ったので対応方法を残しておこうと思います。
きちんと対策しておくことに越したことはないので、
AWSのSES(Simple Email Serve)
を利用する前に気を付けることは下記を参照してください。
https://qiita.com/uzresk/items/bbca7d5acc6c02534682
警告メール
下記のメールを受け取ったらピンチです。
Hello,
There's an issue related to your Amazon SES account that requires your attention. This message contains more information about these issues, and some information that might help you resolve them.
We only change your sending status in order to protect your reputation as a sender, and to ensure that other SES customers' ability to send email isn't impacted. We may pause your account's ability to send email so that you have time to address these issues. When you fix these issues, we'll restore your account's ability to send email.
以下省略
簡単にメールの内容をまとめるとこんな感じです。
- バウンス率が高いのでステータスをレビュー中にします。
- 次の8万通のメール送信でバウンス率が改善しない、またはこのメールへ返信しない場合
SES
の機能に制限をかけます。 - バウンス率上昇の原因、原因への対応内容、その対応によって同様の問題が起きなくなる理由を書いて返信してください。
原因
今回の原因はDBに登録していたメールアドレスが全てhoge@test.com
みたいになっていたので発生してしまいました。
またCloudwatchでの監視も行っていなかったので、テストメールが送信され続けてバウンス率が上昇しても気づきませんでした。
対応
ここからは実際に対応を行っていきます。主に以下の3つです。
- DBに登録されているテストメールをきちんと届くメールアドレスに変更する。
-
CloudWatchAlarm
を設定してバウンス率の上昇を監視する。 - AWSのSESチームにメールを返信する。
他の環境にもすぐに適用できるように2個目はcloudformation
で記述しました。
AWSTemplateFormatVersion: '2010-09-09'
Parameters:
ServiceName:
Description: "input your ServiceName."
Type: String
Default: "app"
Endpoint:
Description: "input your sns topic to mail"
Type: String
Default: "test@test.com(ちゃんと届くメールアドレス)"
Resources:
# ------------------------------------------------------------#
# SES Bounce Number Alart SNS Topic
# ------------------------------------------------------------#
SesSnsTopic:
Type: AWS::SNS::Topic
Properties:
DisplayName: !Sub ${ServiceName}-SES-Alart-Topic
TopicName: !Sub ${ServiceName}-SES-Alart-Topic
SnsSubscription:
Type: AWS::SNS::Subscription
Properties:
Protocol: email
Endpoint: !Ref Endpoint
TopicArn: !Ref SesSnsTopic
# ------------------------------------------------------------#
# SES Bounce Number Alart
# ------------------------------------------------------------#
BounceNumberAlarm:
Type: AWS::CloudWatch::Alarm
Properties:
AlarmActions:
- !Ref SesSnsTopic
AlarmDescription: !Sub ${ServiceName}-SES-Bounce-Number-Alart
AlarmName: !Sub ${ServiceName}-SES-Bounce-Number-Alart
ComparisonOperator: GreaterThanOrEqualToThreshold
EvaluationPeriods: 1
Period: 300
Threshold: 1 #1通でもバウンスメールがあったら通知
MetricName: Bounce
Statistic: Average
Namespace: AWS/SES
# ------------------------------------------------------------#
# SES Bounce Rate Reputation Alart
# ------------------------------------------------------------#
BounceRateAlarm:
Type: AWS::CloudWatch::Alarm
Properties:
AlarmActions:
- !Ref SesSnsTopic
AlarmDescription: !Sub ${ServiceName}-SES-Bounce-Rate-Alart
AlarmName: !Sub ${ServiceName}-SES-Bounce-Rate-Alart
ComparisonOperator: GreaterThanOrEqualToThreshold
EvaluationPeriods: 1
Period: 900
Threshold: 0.03 #バウンス率が3%以上になったら通知。5%未満をAWSは推奨。
MetricName: Reputation.BounceRate
Statistic: Average
Namespace: AWS/SES
# ------------------------------------------------------------#
# SES Complaint Rate Reputation Alart
# ------------------------------------------------------------#
ComplaintRateAlarm:
Type: AWS::CloudWatch::Alarm
Properties:
AlarmActions:
- !Ref SesSnsTopic
AlarmDescription: !Sub ${ServiceName}-SES-Complaint-Rate-Alart
AlarmName: !Sub ${ServiceName}-SES-Complaint-Rate-Alart
ComparisonOperator: GreaterThanOrEqualToThreshold
EvaluationPeriods: 1
Period: 900
Threshold: 0.005 #一応、苦情率が0.5%以上になったら通知。1%未満をAWSは推奨。
MetricName: Reputation.ComplaintRate
Statistic: Average
Namespace: AWS/SES
これでバウンスが発生したときは通知先に登録したメールアドレスに内容が送られてくるようになります。(AWSから登録したメールアドレスに検証リンクが送られてくるので押下して検証済みにする)
対応が終わったら、下記の3点について英語で内容をまとめたうえで、警告メール下部に記載されている返信先にメールを送信します。
全部Google翻訳を活用して英語で返信しました。
* What caused your high bounce rate?
* What changes have you made in your email-sending systems or processes?
* How do these changes ensure that the issue won't occur again in the future?
*
これで次の日には、警告状態を解除してくれました。(その旨のメールが返信されます)
おまけ
バウンスが発生したメールアドレスとかの情報を残しておきたいと思ったので、DynamoDB
にバウンス情報を保持するようなLambdaを作成しました。
構成としてはこんな感じです。
SES→SNSトピック→Lambda→DynamoDB
SESにBounce Notifications SNS Topic
を設定するところがあるのでそれをLambdaのイベントトリガーにする感じです。
const AWS = require('aws-sdk');
const dynamo = new AWS.DynamoDB();
exports.handler = async (event, context) => {
// SNS通知でどんなリクエストが入ってくるのか確認
// console.log(JSON.stringify(event));
// console.log(event.Records[0].Sns);
const getStringMessage = event.Records;
const promises = getStringMessage.map(record => {
const date = new Date();
const createDateUnix = date.getTime();
const getObjectMessage = JSON.parse(record.Sns.Message);
const putParams = {
TableName: "DynamoDBのテーブル名",
Item: {
// DynamoDBのパーティションキー(DynamoDBの設計は適当でごめんなさい)
notificationType: {"S": `${getObjectMessage.notificationType}`},
// DynamoDBのソートキー(DynamoDBの設計は適当でごめんなさい)
timestamp: {"N": `${date.getTime()}`},
// とりあえずもらった内容をそのまんま放り込む。内容はこちらを参照(https://docs.aws.amazon.com/ja_jp/ses/latest/DeveloperGuide/notification-examples.html#notification-examples-bounce)
body: {"S": JSON.stringify(getObjectMessage)}
}
}
return dynamo.putItem(putParams).promise();
});
await Promise.all(promises)
.then(results => {
console.log(results);
})
.catch(reject => {
console.log(reject);
});
};
反省します。
以上です。