# AWS SES メール開封確認  DB に集計

2017 年から AWS が SES のメール開封通知、リンククリックなどの機能をリリースしました。
送信すごとに 1 x 1 ピクセルの透明 GIF イメージが挿入されて、画像が表示されたら開封とみなします。
Gmail のデフォルトでは添付画像を表示させないため、「画像が非表示になっています。下記の画像を表示」をクリックする必要があります。

環境

  • AWS: SES SNS LAMBDA でメール送信
  • PHP: Laravel

メール開封確認の流れ

  • SES メール送信設定
  • SNS 開封すれば発火
  • LAMBDA webhook にアクセス
  • Laravel パラメータ受けて DB 更新

LAMBDA で受け取ったタイミングで DB 更新もできますが、今回は Laravel でパラメータ受けて DB 更新することにしました。
ロジック処理をできるだけ Laravel 側にまとめておきたいので

# SES

AWS SES は Amazon Simple Email Service の略でアマゾンが提供している Email 送信サービスです。

  1. SES Configuration sets 設定
  2. Event destinations 設定
  3. Specify destination 設定
  4. SES Verified identities 設定

# SES Configuration sets 設定

Configuration set name はメール送信時にヘッダーX-SES-CONFIGURATION-SETに追加する

# Event destinations 設定

Event destinations > Add event destination

送信&配信タイプ選択
Open and click tracking > Opens

# メール送信イベント

Amazon SES に送信したメールの結果

SES イベントタイプ 意味 説明
Sends 送信 Amazon SES から送信した
Rendering failures レンダリング失敗 Amazon SES はテンプレートのレンダリングに失敗
Rejects 拒否 Amazon SES または受取メールサーバーに送信拒否された
Deliveries 配信 メールを正常に送信した
Hard bounces ハードバウンス 受取人のメールサーバーにより、メール完全に拒否
Complaints 苦情 正常に配信されたが、受取人がスパムとしてマークした
Delivery delays 送信遅延 受取人サーバーの一時的な問題で配信遅延
Subscriptions 配信停止要求 メール正常に配信、受取人が配信停止要求
Opens オープン 受取人がメール開いたと推測
Clicks クリック 受取人がメールクリックしたと推測

# Specify destination 設定

Amazon SNS を選択して SES 送信して開封確認したら、SNS に通知するように設定

# Destination タイプ

  • Amazon CloudWatch
  • Amazon Kinesis Data Firehose
  • Amazon Pinpoint
  • Amazon SNS

Amazon Simple Notification Service (SNS) topic で新規作成か既存トピックを選択する

# SES Verified identities 設定

Assign a default configuration setにチェック入れる
Default configuration set を先に設定した Configuration set を選択

# Laravel からメール送信

header に X-SES-CONFIGURATION-SET: { #SESで設定するconfig名 } つける

return $this->view('mail.html.mail')
         ->text('mail.plain.mail')
         ->subject($this->subject)
         ->from($this->from)
         ->withSwiftMessage(function (\Swift_Message $message) {
             $message->getHeaders()->addTextHeader('X-SES-CONFIGURATION-SET', 'test-config-set');
         });

# Amazon SES 自動タグ

Amazon SES を使用して送信するメールに自動的に適用される自動タグの一覧

タグ名 説明
ses:configuration-set E メールに関連付けられた設定セットの名前
ses:caller-identity E メールを送信した Amazon SES ユーザーの IAM ID
ses:from-domain 「From」アドレスのドメイン
ses:source-ip 呼び出し元がメールの送信に使用した IP アドレス
ses:outgoing-ip Amazon SES で E メールの送信に使用した IP アドレス

Amazon SES イベント発行を使用して E メール送信をモニタリングする (opens new window)

# SNS

AWS SNS は、Amazon Simple Notification Service の略でアマゾンが提供しているアプリケーション対アプリケーション(A2A)間と、アプリケーション対個人(A2P)間の両方の通信に使用できるメッセージングサービスです。
Cloudwatch のログを拾うなどでよく使われます。

# トピック作成

  • タイプ:スタンダード
  • 名前:入れる
  • 表示名(オプション)

# トピックのサブスクリプションの作成

  • プロトコル:サブスクライブするエンドポイントのタイプ AWS Lambda 選択
  • エンドポイント:作成済みの Lambda 選択

# Lambda

Aws Lambda は、アマゾンが提供しているサーバーレス function サービスです。

  • 関数名
  • トリガーを追加:SNS トピック選択追加
const https = require("https");
const querystring = require("querystring");
const host = "localhost.com";
const path = "/api/post_data";

exports.handler = function (event, context) {
  console.log("Event", event.Records[0].Sns.Message);

  let options = {
    host: host,
    path: path,
    headers: {
      "Content-Type": "application/json",
    },
    method: "POST",
  };

  var post_req = https.request(options, function (res) {
    res.setEncoding("utf8");
    res.on("data", function (chunk) {
      console.log("Response: " + chunk);
      context.succeed();
    });
    res.on("error", function (e) {
      console.log("Got error: " + e.message);
      context.done(null, "FAILURE");
    });
  });
  
  post_req.write(event.Records[0].Sns.Message);
  post_req.end();
};

# Amazon SES E メール送信メトリクスに関するよくある質問

E メールの配信後、いつまで Amazon SES はオープンとクリックのメトリクスを収集しますか?

Amazon SES は各 E メールの送信後 60 日間、オープンとクリックのメトリクスを収集します。

ユーザーが特定の E メールを複数回開くか、特定の E メール内のリンクを複数回クリックした場合、これらの各イベントが別個に追跡されるのですか?

受信者が E メールを複数回開いた場合、Amazon SES によって各オープンが一意のオープンイベントとしてカウントされます。同様に、受信者が同じリンクを複数回クリックすると、Amazon SES によって各クリックは一意なクリックイベントとしてカウントされます。ただし、上記の注釈欄に記載したシナリオによって、これらのカウントが歪む可能性があります。

オープンとクリックのメトリクスは集約されますか? または受取人レベルで測定できますか?

オープンとクリックは、受取人レベルで追跡されます。オープンとクリックの追跡により、E メールを開いた受信者や E メール内のリンクをクリックした受信者を判断できます。

Amazon SES API を使用して開封とクリックのメトリクスを取得できますか?

Amazon SES API は、開封とクリックのメトリクスを取得するメソッドを提供していません。ただし、CloudWatch API を使用して Amazon SES のオープンとクリックのメトリクスを取得できます。たとえば、AWS CLI を使用して、以下のコマンドを発行することで、 CloudWatch API を使用してクリックメトリクスを取得できます。

オープンの追跡はどのように行われますか?

Amazon SES を通じて送信される E メールごとに、1 x 1 ピクセルの透明 GIF イメージが挿入されます。E メールには、このイメージファイルへの固有のリファレンスが含まれており、このイメージがダウンロードされると、どのメッセージを誰が開いたかを SES で正確に判断できます。

デフォルトでは、このピクセルは E メールの下部に挿入されます。ただし、E メールプロバイダーのアプリケーションによっては、特定のサイズを超えると E メールのプレビューが切り捨てられ、メッセージの残りの部分を確認するためのリンクが表示される場合があります。このシナリオでは、SES ピクセルの追跡イメージはロードされず、追跡しようとしているオープン率は破棄されます。これを回避するには、必要に応じて E メールの本文に {ses:openTracker} プレースホルダーを挿入して、E メールの先頭または他のいずれかの場所にピクセルを配置します。プレースホルダーを含むメッセージを SES が受信すると、そのメッセージはオープンの追跡ピクセルイメージに置き換えられます。プレースホルダーを 1 つ追加すると、最初の出現箇所だけが置き換えられ、残りの部分は省略されます。

この追跡用のピクセルを追加しても、E メールの外観は変わりません。

オープンの追跡はデフォルトで有効になりますか?

オープンの追跡は、デフォルトですべての Amazon SES ユーザーに利用可能です。オープンの追跡を使用するには、以下の操作を行う必要があります。

オープンの追跡用ピクセルを特定の E メールから除外できますか?

オープンの追跡用ピクセルを E メールから除外するには 2 つの方法があります。最初の方法では、設定セットを指定しないで E メールを送信します。別の方法として、オープンイベントに関するデータを発行するように設定されていない設定セットを指定できます。

プレーンテキストメールのオープンは追跡されますか?

オープンの追跡の対象となるのは HTML メールのみです。オープンの追跡にはイメージの挿入が必要であるため、ユーザーがテキスト専用 (HTML 以外) の E メールクライアントで E メールを開くと、オープンメトリクスを収集することはできません。

クリックの追跡はどのように行われますか?

クリックを追跡するには、Amazon SES で E メールの本文の各リンクを変更します。受信者がリンクを開くと、オープンは Amazon SES サーバーに送信され、即座に送信先アドレスに転送されます。オープンの追跡と同様に、各転送先リンクは一意です。これにより、リンクをクリックした受信者、クリックした時間、リンク元の E メールを Amazon SES で判断できます。

クリックの追跡を無効化できますか?

E メールの HTML 本文のアンカータグに ses:no-track 属性を追加することで、個々のリンクのクリック追跡を無効にできます。たとえば、AWS ホームページにリンクする場合、通常のアンカーリンクは次のようになります。

<a ses:no-track href="aws.amazon.com">Amazon Web Services</a>

ses:no-track はスタンダードの HTML 属性ではないため、受信者の受信トレイに届く E メールのバージョンから Amazon SES によって自動的に削除されます。

各 E メールで追跡できるリンクの数はいくつでしょうか?

クリック追跡システムでは、最大 250 のリンクを追跡できます。

プレーンテキストの E メールのリンクに対するクリックメトリクスは収集されますか?

HTML E メールのクリックのみを追跡できます。

リンクに一意の識別子をタグ付けできますか?

ses:tags 属性を使用すると、メール内のリンクにキーと値のペアとしてタグを追加できます。追加できるタグの数に制限はありません。この属性を使用する場合は、CSS インラインプロパティを渡す場合と同じ形式を使用してキーと値を指定します。この形式では、キーの後にコロン (😃、その後に続けて値を入力します。複数のキー値ペアを渡す必要がある場合は、各ペアをセミコロン (😉 で区切ります。

たとえば、リンクにタグとして product:book genre:fiction subgenre:scifi type:newrelease を追加するとします。この場合、結果のリンクは次のようになります。

<a
  ses:tags="product:book;genre:fiction;subgenre:scifi;type:newrelease;"
  href="http://www.amazon.com/"
  >New Releases in Science Fiction</a
>

追跡されるリンクは、HTTP または HTTPS プロトコルを使用しますか。

リンクの追跡には E メールの元のリンクと同じプロトコルを使用します。

追跡されている E メール内のリンクはありませんの理由

Amazon SES では、E メール内のリンクに適切にエンコードされた URL が含まれています。具体的には、リンク内の URL は、RFC 3986 に準拠している必要があります。E メールのリンクが適切にエンコードされていない場合は、受信者は E メールにリンクを表示できますが、Amazon SES はそのリンクのクリックイベントを追跡しません。

不適切なエンコードに関連する問題は、通常、クエリ文字列が含まれている URL で発生します。

## 参考

2022-08-13
  • server
  • aws
  • laravel

関連記事

Laravel メンテナンスモード
XZ Utils 事件対応
Laravel model で hidden に設定したカラムを一時解除
Laravel でカテゴリー作成 テーブル構築と再帰クエリ
Laravel Queue で非同期処理
Laravel notification メール通知カスタマイズ
Laravel lang バリデーションメッセージを多言語対応
Ubuntu で Web サーバーを構築する手順
Laravel を API サーバーとしての初期設定
メールサーバー移行と POP & IMAP 設定
Laravel リクエストログ出力
Laravel 429 Too Many Requests
Docker Supervisor 使ってバッチ処理
Laravel Email バリデーションについて
よく使う WSL コマンド
Laravel Sanctum 使って API トークン JWT 認証と SPA 認証
自宅サーバー構築!  Nextcloud で NAS クラウドストレージ
no such file or directory: /usr/share/zsh/vendor-completions/_docker
oh my zsh 使うべし
AWS Lambda Nodejs で chatwork へ post 送信
AWS CloudWatch ログ監視で Lambda 処理
Laravel logger でエラーログを chatwork に自動送信
Vim 操作とショートカット
Laravel tinker 使って DB データベース接続とコマンド
Laravel Test についてのメモ
Laravel Log の基本設定&使い方
DDNS 無料ダイナミック DNS サービス 4 つ
Nginx 基本設定
Laravel Sail で Docker 環境構築
Laravel Lumen Faker 日本語設定
SPF メール送信なりすまし対策
Windows Mac Linux hosts ファイル場所
laravel method の基本 get post put options
Laravel schedule 設定
AWS Unresolved resource dependencies [AWSEBV2LoadBalancer] エラー
ディスク容量を確認する df コマンド
Laravel eloquent model の規約
Laravel Address already in use の原因
content-security-policy 設定
AWS Elastic Beanstalk php.ini 設定変更
Laravel timestamp() auto update 有効化無効化
AWS Elastic Beanstalk 環境設定
Laravel toSql パラメータ付きで出力
AWS のタイムゾーンを UTC 協定世界時から JST 日本標準時に変更
Docker の基本的な使い方
Amazon DynamoDB 制限調査
Laravel blade foreach loop と current url
laravel session を制する
AWS 504 Gateway Timeout エラー対応
Shell と Bash のいろいろ
Mac ターミナル SSH 接続設定
Elastic Beanstalk \$\SERVER['REMOTEADDR'] 取得できない
crontab 設定いろいろ
AWS EC2 の amazon-linux-extras の話
デプロイツール Capistrano
Laravel 5.1 から 8.1 にバージョンアップ
解決! xserver php バージョンアップした時に ssh 環境に反映されない
youtube 見れるように vpn サーバー建ててみた
xserver に vim インストール
xserver に nodejs インストール
レンタルサーバーなら xserver おすすめ理由
Lumen と Laravel 違い比較
Docker command でドッカー練習する時のメモ
Windows10 Home に Docker 入れた時のメモ
Centos7 Webserver 構築の時のメモ
Laravel Error についてのメモ
laravel に vuejs 使うための初期設定