Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
4
Help us understand the problem. What is going on with this article?
@haratai

AWS SESバウンス率上昇警告への対応

More than 1 year has passed since last update.

はじめに

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で記述しました。

cloudWatchAlarm.yaml
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のイベントトリガーにする感じです。

index.js

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); 
    });

};

反省します。
以上です。

4
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
haratai
bigtreetc
お客様のデジタルトランスフォーメーションの実現をミッションとして、DXに欠かせない「クラウド」「AI」「デジタルマーケティング」「RPA」をコアテクノロジーとして位置付け、各テクノロジーのプロフェッショナルチームにより専門的なサービスを提供しています。

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
4
Help us understand the problem. What is going on with this article?