ユアマイスター株式会社エンジニアブログ

ユアマイスター株式会社のエンジニアが日々徒然。

Sendgrid Event Webhook + Lambda + RDS Proxy + RDSでバウンスメール撲滅&メール開封率計測をする

f:id:yourmystar_engineer:20201217140727j:plain

どうも。ユアマイスター星(@inase17000)です。

このブログもしばらくイベントやニュースの告知だけになってしまっていました。。。 今回は久しぶりの技術記事。先日から利用をしているSendgridとAWSの機能紹介と、恥ずかしながらハマったところをシェアします。

それでは行ってみましょう!

前提条件

ユアマイスターではシステムからメールを送信するときに、Sendgridというメール配信サービスを利用しています。

ユーザがご自身でフォームに入力したメールアドレスに対して、メールを送信するのですが、どうしても誤字脱字の記入ミスや、他のいろいろな理由により、メールが届かないことがあります。

その結果、ユーザへの連絡に気づいてもらえなかったり、システムのフローにおいて支障をきたすことになるので、定期的にお問い合わせの発生やトラブルの原因となるリスクを孕んでいました。

システムからSendgridへはSMTPでリクエストを行なっており、そのメール配信結果はSendgridの管理画面上で確認が可能です。

f:id:yourmystar_engineer:20201217073901p:plain
Sendgridの管理画面

引用:メールが届いているか確認する - ドキュメント | SendGrid

が、しかし、最長7日間...24時間その管理画面に張り付いているわけにもいかないので、この検知と改善に向けたアクションを自動化しようと考えました。

ところで、バウンスメールって何?

バウンスメールとは、受信側のメールサーバが原因で、正しく配信できなかった場合のメールのことをいいます。

ソフトバウンスは、メールアドレスが正しく、受信者のサーバに到達したが、以下の様な理由で返されたということを意味します。

  • メールボックスが一杯だった
  • サーバがダウンしていた
  • メッセージサイズが大きすぎた

ハードバウンスは、以下の様な理由で受信を恒久的に拒否された場合に発生します。

  • メールアドレスが無効/不正
  • メールアドレスが存在しない

引用:バウンスメールとその対策 | SendGridブログ

f:id:yourmystar_engineer:20201217064410p:plain
ソフトバウンスとハードバウンスのイメージ図

上記のようなイメージ図にあるとおり、ソフトバウンスは軽めのバウンドをしていてそのうち戻ってきそうなイメージで、ハードバウンスはすっっごいバウンスしているからもう戻ってきなそうなイメージです。(第一宇宙速度を突破したと考えてよい)

ソフトバウンスの方は完全にエラーアドレスと判断しないでもよいということ。まだ復帰する可能性があるため、少しの間様子を見てみることが必要です。

一方、ハードバウンスの方は完全にエラーアドレスという判断をして、このメールアドレスにはメールを送ることができないため、正しいメールアドレスに変更してもらうようにユーザへ依頼する必要があります。

なんでそんなことするの?

スパム認定のリスクを下げたい!

エラーメールアドレスを多く含む(エラー率が高い)メール配信は、スパムメールとして認識される確率が高まります。

ひとたびスパムメールとして認識されてしまうと、メール配信元のIPアドレス単位(またはドメイン単位)でメール配信が行えなくなってしまいます。つまり、全ユーザにメールが送れなくなるということですね。

この「スパムメールとして認識されるかどうか」には種類があって、IPレピュテーションとドメインレピュテーションがあります。

IPレピュテーション

メールの送信元を一意に識別するものとして『IPアドレス』があります。共有のIPアドレスからメールを送信する企業もありますが、これは複数の企業が同じIPアドレスからメールを送信するということです。大量のメールを送信する場合、普通は自分の組織が保有している固定IPアドレスから送信します。固定IPアドレスを使うことで、他の送信者の不適切な振る舞いに影響されることがなくなるため、IPレピュテーションをコントロールしやすくなります。

ドメインレピュテーション

ドメインレピュテーションは、IPアドレスではなく、送信元ドメインベースの指標です。つまり、ISPのフィルタリングの判定ではブランド(ドメイン)が優先されるということです。 IPv4からIPv6への移行に伴い、ドメインレピュテーションへの関心が高まりました。ドメインレピュテーションはまだ一般的な技術ではありませんが、(Gmailが強く支持する)IPv6では必須とされていることもあり、完全にIPv6に移行されるまでIPレピュテーションとドメインレピュテーションを併用するISPが出てきました。

引用:IPレピュテーション vs. ドメインレピュテーション【入門】 | SendGridブログ

メール送信元のIPをころころ変えて回避しようとしても、ドメインが一緒だったらやっぱりスパムメール判定から逃れられないということなので、ちゃんと真っ当にサービスを運営していきましょうという話です。ちなみに、このレピュテーションの度合いを確認する方法もあるみたいなので、使ってみてください。

どうやって実現するか?

さて、前置きが長くなりましたが、実際の構成について話していきましょう。

f:id:yourmystar_engineer:20201217090015p:plain
処理の流れ

流れを大まかに書いて見ると

①メールISPからSendgridがメール受信できなかったレスポンス取得

②Sendgridが「Event Webhook」起動

API Gateway経由でLambdaの関数にPOST

④Lambda関数によりRDSへデータの登録

となります。

それぞれの設定で参照したページをリンクしておきます。

技術的な考慮点の中で特に考えたことは3つあります。

トラフィック

SendgridのEvent Webhookでは、1送信あたり少なくとも2回はLambdaがコールされることになります。

そのメールが開封されたり、コンテンツ内のリンクがクリックされた場合はさらに2回以上追加されます。

1送信あたり5回コールされると考えたときに、月間のメール通数が100万通と仮定すると、月間500万回。これは現在のユアマイスターのサーバ構成においては、無視はできないトラフィック量でした。

WebサーバでAPIを実装して受け止める案も考えましたが、メール通数が増えていったときに、そのためだけにWebサーバをスケールアウトしなければいけなくなるのが辛いなと思い、単純にDBにデータを登録するだけのLambdaで受け止める案に決定しました。

ざっくり書いてはいますが、実際は技術選定プロセスを経て意思決定を行っています。

②運用コスト

Lambdaの料金体系 を見ると、

  • リクエスト数に応じた従量課金
  • 処理時間に応じた従量課金

であることがわかります。

今回、月間500万回〜くらいのリクエストになることが予想されているので、費用としては多くとも数千円で、問題ない範囲でした。

ちなみに、AWSのコスト概算が計算できるサイトもありますので、参考にしてみてください。便利!

③ユアマイスターのデータとの紐付け

Sendgrid Event Webhookでは、カスタマイズのできるパラメータを持たせることができます。

ユアマイスターでは、Sendgridにメール送信のSMTPリクエストを送信しています。

これは、X-SMTPAPIヘッダを付与することで実現できます。

メール送信処理時に、JSON形式で

{
  "unique_args": {
    "order_id": "55555",
    "user_id": "6666666",
    "New Argument 1": "New Value 1",
    "New Argument 2": "New Value 2",
    "New Argument 3": "New Value 3",
    "New Argument 4": "New Value 4"
  }
}

といった形式で、X-SMTPAPIヘッダに値を付与するように実装しました。弊社ではCakePHP3にてメール送信ロジックを開発しているため、CakePHP3のEmail::setHeaders()を使いました。

そうすることで、Sendgrid Event Webhookのレスポンスに、

[
  {
    "event": "Processed",
    "timestamp":"123456789",
    "order_id": "55555",
    "user_id": "6666666",
    "New Argument 1": "New Value 1",
    "New Argument 2": "New Value 2",
    "New Argument 3": "New Value 3",
    "New Argument 4": "New Value 4",
    "email": "john.doe@sendgrid.com"
  }
]

こんな形で入ってきますので、これをLambdaでパースしてDBに登録します。

このカスタムパラメータに、関連するユーザIDや注文IDを入れておくことで、Webアプリケーションのデータと紐付けることが可能となります。

その後の話

上記の実装を行って、SendgridのEventデータを蓄積していくことで得られたメリット、それはメールに関する実績データが見える化できるようになったということです。

メールは送ったら送りっぱなしではいけなくて、そこに記載された情報が相手に届いているかというのがとても重要です。一方通行ではなくその結果まで見ながら、ユーザの利便性を向上できるアイディアがいくつかあったので、早速試してみたことを紹介します。

ハードバウンスになったメールアドレスについては、メアド誤り・意図的な嘘メアドの可能性が高いため、別手段でユーザに連絡をとり、正しいメールアドレスを登録し直してもらいます。そうして、バウンスメール撲滅により、ユーザと連絡がつかずにご迷惑をおかけすることを防ぐのに役立てることができるようになりました。

また、メール開封率計測により、メールテンプレートごとのタイトルやコンテンツの改善活動に役立てることもできます。その他にも、時間帯ごとのメールの利用動向がつかめたり、ユーザごとにメールの利用動向もわかりますので、今後のパーソナライズの仕組みに活かしていこうと思います。ちなみに、メールの中にある導線のクリックイベントも取得できることから、パーソナライズしながらメールテンプレートの自動出し分けというのも可能になっていきますね。楽しみです。

以上です!

ユアマイスター では一緒にはたらくエンジニアを募集しています。

▼お気軽にご連絡ください▼

https://corp.yourmystar.jp/recruit

お気軽にご連絡お待ちしてます!!

追伸

新アプリケーションを立ち上げるときに、メール配信処理のようなところは自前でどうにか作り込むよりはAWSのSESやSendgridのようなメール配信プラットフォームを利用することが当たり前にあります。自分でバウンスメールの処理書かなくていいの本当に便利。前職ではこれをゼロから実装したおぼえがあり、受信側のメールサーバのステータスコードをひとつずつ解明してソフトバウンスとハードバウンスを寄り分けた記憶が。。。時代の流れを感じる。。。