ブログ

AWS で Amazon SES のバウンス通知を実装する方法

簡単に到達率の高いメール送信機能が実装できる Amazon SES、料金も安いため導入されやすいのですが Amazon SES 特有の注意点もあります。

その一つがバウンス・苦情率の管理です。

Amazon SES 以外でも気をつけるべき事柄ですが、一定以上のバウンス・苦情率になると AWS から Amazon SES の利用を停止されてしまいます。メール送信はシステムでも重要な役割を担うことが多く、停止されないように正しくバウンス・苦情通知の処理を実装しておくことをおすすめします。

今回はバウンス通知に対する処理方法をご紹介します。

Amazon SES でこんな通知が来たら要注意 ─ AWS からのバウンス率上昇通知

AWS ではバウンス率は2%未満での運用を推奨しています。

バウンス率が5%を超えた場合、そのアカウントはレビュー対象となり以下のようなサポートケースが作成されます。

件名:

Amazon SES Bounce Review Period for AWS Account [AWSアカウントID]

本文(抜粋):

```

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.

~~~~~

```

要約すると下記3点の対応と報告が求められます。

  1. バウンスになったメールアドレスへ今後送信しないように処置実装
  2. バウンス原因の特定
  3. 2 に基づいて送信プロセスまたは手順を変更

AWS はなぜ Amazon SES でバウンス率を重視するのか

送信側は相手のメールボックス(受信サーバー)に届けば目的が達成されるため、悪意のあるメールが多く届きます。そのため受信サーバーは様々な方法でそのメールが健全なものであるか判断しています。
(SPF, DKIM, DMARC, バウンス率, 苦情率 etc.)

DKIM, DMARC 等は送信メールドメイン単位で健全性が判断されますが、バウンス率と苦情率が悪化すると送信サーバーの IP アドレス単位で判断されます。例外はありますが Amazon SES の IP アドレスは AWS が保有しており、もしその IP からのメールすべてがスパムと判断されてしまうと Amazon SES を利用する全アカウントがスパムと判断される可能性があります。そのためバウンス率が上昇すると他アカウントを守るために Amazon SES の利用を停止します。

補足としてバウンスにはソフトバウンスとハードバウンスの2種類があります。ソフトバウンスはメールボックスの容量がいっぱいであったり、接続数が多いなど一時的な障害です。ハードバウンスは存在しないメールアドレス、受信サーバーがスパムと判断し受信を拒否など永続的な障害です。

バウンス率に計上されるのはハードバウンスになります。

バウンス通知処理 AWS コンソール設定手順

バウンス時にシステムへその情報を送信する方法を解説していきます。

◎ SNS トピックを作成

SNS コンソールから [トピックの作成] を選択

タイプ:スタンダード
名前:任意
上記以外はデフォルトのまま [トピックの作成] を選択

[サブスクリプションの作成] を選択

プロトコル:HTTPS
エンドポイント:用意した自動処理システムの URL
上記以外はデフォルトのまま [サブスクリプションの作成] を選択

この時点でエンドポイントに対してメッセージが正しく受け付けられるか HTTP リクエストが発生します。専用の処理を実装する必要があるので、その方法は次章で解説します。

ステータスが [確認済み] になっていれば成功です。
[保留中の確認] となっている場合はエンドポイントが正しく受け付けられていない可能性があります。

◎ Amazon SES でバウンス時の動作を設定

Amazon SES の ID 画面からバウンス通知を設定したい ID を選択

通知タブからフィードバック通知の [編集] を選択

バウンスフィードバックに先ほど作成した SNS トピックを指定
[元のEメールヘッダーを含める] を有効化
上記以外はデフォルトのまま [変更の保存] を選択

フィードバック通知の Bounce に SNS トピックが表示されていれば完了です。

バウンス通知処理 アプリケーション実装

SNS のサブスクリプション作成時とバウンス通知時の処理を解説します。

先程のエンドポイントでは以下のような処理を実装しています。

<?php
// リクエストを取得
$postData = file_get_contents('php://input');

// ヘッダを取得してSNSメッセージタイプを確認
$headers = getallheaders();
$messageType = isset($headers['x-amz-sns-message-type']) ? $headers['x-amz-sns-message-type'] : '';

// リクエストからSNSメッセージをデコード
$snsMessage = json_decode($postData, true);
$sesMessage = json_decode($snsMessage["Message"],true);

switch ($messageType) {
    case 'SubscriptionConfirmation':
        // SubscribeURLにGETリクエストしてサブスクリプションを成功させます
        file_get_contents($snsMessage['SubscribeURL']);
        
        echo 'Subscription confirmation sent.';
        break;

    case 'Notification':
        // 実際の通知処理をここに記述します
        if($sesMessage["notificationType"] == 'Bounce' && $sesMessage["bounce"]["bounceType"] == 'Permanent'){
            $bouncedRecipients = $sesMessage["bounce"]["bouncedRecipients"];
            $bouncedEmails = array();
           foreach($bouncedRecipients as $bouncedRecipient){
                //バウンスとなったメールアドレスを配列に格納
                $bouncedEmails[] = $bouncedRecipient["emailAddress"];
           }
           file_put_contents("./file/address_".time(),json_encode($bouncedEmails),FILE_APPEND);
        }   
        echo 'Notification processed.';
        break;

    case 'UnsubscribeConfirmation':
        // サブスクリプション解除の確認処理をここに記述します
        echo 'Unsubscribe confirmation processed.';
        break;

    default:
        // 不明なタイプの場合はエラーを返します
        header('HTTP/1.1 404 Not Found');
        echo "Unknown message type: " . $messageType;
        break;
}
?>

◎サブスクリプション時

file_get_contents($snsMessage['SubscribeURL']);

サブスクリプション時にエンドポイントへ検証用の URL を渡すので、その URL へ GET リクエストをすることでサブスクリプション作成が成功します。

バウンス時にはこの URL は渡されないので、Switch 文などで分けておきます。

◎バウンス時

 if($sesMessage["notificationType"] == 'Bounce' && $sesMessage["bounce"]["bounceType"] == 'Permanent'){
            $bouncedRecipients = $sesMessage["bounce"]["bouncedRecipients"];
            $bouncedEmails = array();
           foreach($bouncedRecipients as $bouncedRecipient){
                //バウンスとなったメールアドレスを配列に格納
                $bouncedEmails[] = $bouncedRecipient["emailAddress"];
           }
           file_put_contents("./file/address_".time(),json_encode($bouncedEmails),FILE_APPEND);
        }   

今回は notificationType と bounceType を条件にメールアドレスを収集しています。

どのようなタイプがあるかは AWS の開発者ガイドを参考にしています。

Amazon SES の Amazon SNS 通知コンテンツ - Amazon Simple Email Service
https://docs.aws.amazon.com/ja_jp/ses/latest/dg/notification-contents.html#bounce-object

また検証用の処理であるため、該当メールアドレスをファイル出力のみしていますが実際はユーザーマスタ等のレコード変更処理を実装すると良いかと思います。

バウンス通知処理 動作検証

実際にバウンスさせて動作検証させる場合、AWS が用意したメールアドレスを使用します。

[テストEメールの送信] を選択

From-address:任意
シナリオ:バウンス
件名:任意
上記以外はデフォルトのまま [テストEメールの送信] を選択

適当なメールアドレスを使用するとバウンス率が増加しますが、このような手順でバウンス率を増加させずバウンス通知の動作検証が可能です。

AWS で Amazon SES のバウンス通知を実装する方法(まとめ)

本ブログでは、 Amazon SES の バウンス通知の実装方法をご紹介いたしました。

今回ご紹介した Amazon SES の設定をはじめ、ターン・アンド・フロンティアでは AWS をご利用されているお客様に技術的なご支援が可能ですので、Amazon SES の活用にご興味のある方は お問い合わせフォーム よりお気軽にご相談ください。

元記事発行日: 2024年06月10日、最終更新日: 2024年06月07日