AWS SESのバウンスメール情報をアプリケーション側で受け取ってみる

はじめに

開発の要件として、アプリケーションからのメール送信時に、
宛先が到達不可能なメールアドレスだった場合に、
そのメールアドレス宛に再度アプリケーションからメールが送られないようにする必要がありました。
今回は、現在使用しているAWSサービスのSimpleEmailService(以下、SESと記載)のバウンスメール情報を、
アプリケーション側で受け取る方法を説明します。

環境

PHP:8.3.7
Laravel:12.3.0

アプリケーション側の設定

アプリケーション側でバウンスメール情報を受け取る準備をします。
今回はPHP+Laravelで実装を行いましたが、
指定したアドレス宛にPOSTでパラメータを受け取れれば何を使ってもOKです。

まず実際の処理を行うControllerを作成します。
後述するSES設定で使用するサブスクライブ用のURLは、
今回ログに出力するようにしています。

App\Http\Controllers\SesBounceController.php

<?php

namespace App\Http\Controllers;

use App\Models\UndeliverableMailAddress;
use Carbon\Carbon;
use Exception;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;

class SesBounceController extends Controller
{
  public function handleBounce(Request $request): \Illuminate\Http\JsonResponse
  {
    // JSON通知データを取得
    $message = json_decode($request->getContent(), true);

    // サブスクライブ用のURLをログに表示する
    Log::channel('daily')->info($message['SubscribeURL'] ?? "", [
      "file" => __FILE__,
      "line" => __LINE__
    ]);

    // "Message"フィールドをデコード
    $notification = json_decode($message['Message'] ?? '', true);

    if (
      isset($notification['notificationType']) &&
      $notification['notificationType'] === 'Bounce'
    ) {
      // バウンスイベントである場合
      $bouncedRecipients = $notification['bounce']['bouncedRecipients'];

      foreach ($bouncedRecipients as $recipient) {
        $emailAddress = $recipient['emailAddress'];

        // メールアドレスを使ってDBに登録するなど。今回はログにメールアドレスを出力します。
        Log::channel('daily')->info($emailAddress, [
          "file" => __FILE__,
          "line" => __LINE__
        ]);
      }
    }

    return response()->json(['message' => 'Bounce processed']);
  }
}

次にルートの設定をします。
先ほど作成したControllerで処理を受け取れるようにします。

routes\api.php

<?php

use Illuminate\Support\Facades\Route;

// sesのバウンスを受け取る
Route::post('ses/bounce', [App\Http\Controllers\SesBounceController::class, 'handleBounce']);

これでアプリケーション側の設定はOKです。

SNSの設定

アプリケーション側へのバウンス通知は、
AWSサービスのSimpleNotificationService(以下、SNSと記載)を使用します。
まずは赤枠のボタンからトピックを作成します。

タイプはスタンダードを選択し、
名前と表示名はお好みで問題ありません。
入力できたら、画面下部にあるトピックの作成ボタンを押下します。

トピックが作成できたら、
次はサブスクリプションの作成を行います。

トピックARNはそのままで、
プロトコルはHTTPSを選択します。
エンドポイントにはroutes\api.phpで設定したURLを入力します。
入力できたら、画面下部のサブスクリプションの作成ボタンを押下します。

サブスクリプションが作成できたら、
トピックの詳細画面に戻りましょう。
サブスクリプションが追加され、ステータスが「保留中の確認」になっていることが確認できます。

ここまでできたら、
アプリケーション側のログを確認してみましょう。
先ほどControllerでサブスクライブ用のURLをログに出力するようにしているので、
ログにサブスクライブ用のURLが出力されているはずです。
そのURLにアクセスするとサブスクライブが完了します。
※ログに出てこない場合は、リクエストの確認ボタンを押してみてください。
再度エンドポイントに対してリクエストが送られます。
それでも出てこない場合は、リクエストが届いていない可能性が高いです。
IP制限などの設定を確認してください。

サブスクライブが完了すると、
サブスクリプションのステータスが「確認済み」になります。
これでSNSの設定はOKです。

SESの設定

最後にSESの設定になりますが、
既にID設定が完了していることを前提に進めます。
まずメール送信に使用しているメールアドレスもしくはドメインの詳細ページに移動します。

詳細ページの下部で、通知タブを押下します。
フィードバック通知という項目が出てくるので、
編集ボタンを押下します。

編集画面で、バウンスフィードバックに先ほど作成したトピックを設定します。
設定出来たら変更の保存ボタンを押下します。

これですべての設定が完了となります。
あとは実際にバウンスになるメールを送ってみるなり、
SESの機能の「テストEメールの送信」をやってみるなりして、
動作を確認しましょう。

まとめ

以上がSESのバウンスメール情報をアプリケーション側で受け取る方法でした。
今回この対応を実施する中で、バウンスメールに関しての気づきがありました。
SESのバウンスメールは、すぐ返ってくる場合もあれば、数時間~数日かかる場合もあるらしく、
送信先のメールサーバーによっては、バウンスが発生しない場合もあるらしいです。
何とも曖昧な基準なのだと感じました。。。

--------------------------
開発支援・技術研修のご要望・ご相談はこちらから
--------------------------
【この技術ブログを読んだエンジニアの皆様へ】
カサレアルブログをお読みいただき、ありがとうございます!

私たちは、常に新しい技術に挑戦し、ユーザーのニーズに応えるサービスを提供しています。
もし、当社の技術への情熱や、会社・チーム・社員の雰囲気に共感いただけたなら、
ぜひ私たちと一緒に働きませんか?
現在、株式会社カサレアルでは事業拡大に伴い、新たな仲間となるエンジニアを積極的に募集しています。

少しでも興味をお持ちいただけましたら、まずは弊社のことを知っていただけると嬉しいです。
▼採用サイト
https://www.casareal.co.jp/recruit/career
▼社員インタビュー
https://hrmos.co/pages/casareal/jobs/0000016
▼エンジニアの仲間になる! エントリーはこちらから
https://hrmos.co/pages/casareal/jobs

皆様のエントリーを心よりお待ちしています!

AI Assistantで実現するレビュアーの負荷軽減とコードレビュー「統一基準」

コメントを残す

メールアドレスが公開されることはありません。 ※ が付いている欄は必須項目です

コメント ※

名前 ※

メール ※

サイト