FundsでのHTMLメールレンダリング

今回はかなりニッチなネタですが、HTMLメールについて。

Funds のサービスから自動的に送付するメールは、HTML/テキストの両方を含むマルチパートメールとして送信しています。

HTMLメール自体はあまりサービスにおいて本質的なものではありませんが、今回は昨年行った、このHTMLメール送信のサービスを切り出した話を述べてみたいと思います。

マルチパートメールの仕組み

まずはじめに、HTMLメールで使用されるマルチパートメールの仕組みを簡単に説明しておきます。

マルチパートメールでは、次のように複数の Content-Type セクションから構成されます。

Content-Type: multipart/alternative --boundary="(バウンダリ文字列)"

------(バウンダリ文字列)
Content-Type: text/plain ...
(以下テキストパートのBODY)

------(バウンダリ文字列)
Content-Type: text/html ... 
(以下HTMLのBODY)

通常、ほとんどのHTMLメールはHTML非対応のメールクライアントでも読めるように、マルチパート形式のメールとなっています。またメールを送信するサービスによっては、HTMLパートのみで構成されるメールから、自動的にテキストパートも生成してくれるよう場合もあります。

メールクライアントの方では、HTMLメールに対応しているメールクライアントであればHTMLパートのコンテンツを元にHTMLメールとして表示します。一方HTML非対応のメールクライアント、もしくはメールクライアントの設定等によりHTMLメールを受け付けない場合には、テキストパートのコンテンツを元にテキストメールで表示されるという仕組みです。

通常のメールはテキスト形式であることが基本なので、HTMLメールを送付する際には、このようにHTMLパートとテキストパートの両方を含めて送ることが一般的です。

HTMLメールのレガシーさ

2021年という現在おいても、HTMLメールはかなり古き時代のHTMLを知る必要があります。一例を挙げると

・Gmail などのWebメールも含め、メールクライアントによってサポートが異なる
・CSS にクラス名を認識しないメーラーもあるため、インラインスタイルで指定する
・CSS3 で用意されているような Flexbox ももちろん使用できないので、幅広いメールクライアントに対応させるには、レイアウトはテーブルレイアウトを利用する

といった具合です。

単なるマークアップであっても、2020年代のWebとしては非常に辛いものがあります(10年前でも十分辛いですが)。

react-html-email によるHTMLメールの実装

このようなマークアップのしづらさを解決するため、 Funds にHTMLメールを導入する際は、 react-html-email を利用していました。

この react-html-email は、React のコンポーネントとして表示を実装すると、その出力として正しく表示可能なHTMLを出力できるというライブラリです。

所定のブラウザで対応していない CSS プロパティを指定した場合、非対応ブラウザがあることを教えてくれるにとどまります。そのため実際にメーラーでも期待通りの表示が得られるかどうかは、実際のメーラーあるいは Litmus のようなサービスを使用してチェックしていく必要があります。

とはいえHTMLメールをなんのツールのサポートも得られない状態で実装するよりは遥かにマシな実装体験を得ることができます。

一方メールの送信はバックエンドのシステムから送信する仕組みで実装していました。そのため、一度 react-html-email で生成した HTML を Play Framework のコンポーネントである Twirl のテンプレートとして変数を埋め直す方法を取っていました。

この方法によって、HTMLメールを送信することはできるものの、

・メールのテンプレートを変更する場合に、 react-html-email ベースのテンプレートと Twirl のテンプレート双方を修正しなければならず非効率
・Funds のメールでは SES を利用しているので、HTMLパートとテキストパートの両方のテンプレートを用意する必要がある
・最終的にアプリケーションが送信するメールの表示を、事前に確認するのが難しい

といった課題がありました。

HTMLメールのレンダリングサービスによる解決

上記の課題に対して Node.js + TypeScript によるHTMLメール専用の internal なレンダリングサービスを用意し、内部的に利用させることで解決させました(黄色が今回追加したサービスです)

Funds email rendering service - 掲載用 (1)

レンダリング機能に限り別サービスとして切り出し、HTMLパート・テキストパートを出力できるようにしました。既存のバックエンドサービスでは、メール送信に必要なデータの解決と、レンダリングされたコンテンツをメールとして送信する機能を担当する形です。

また、このサービスへ直接アクセスした場合にHTMLメール用をブラウザ上でプレビューできる仕組みなども用意することで、HTMLメールの表示確認や変更についてもメンテナンスしやすい形としました。

このサービスは新規で動作するので、これまでEC2ベースで運用していたアプリケーションをEKSで動作させる1つの契機として、EKS上で動作させています。このあたりはEC2からEKSにシステムを載せ替えしている話も併せてご覧ください。

本質的には、このサービス上から直接メールを送信してもよさそうです。ただしメールを送信するサービスとして機能させる場合、メールの送信が失敗した場合のリトライ機構など、このサービスとして考慮すべき観点が広がります。そのため移行コストを小さくするため、まずはミニマムなサービスとしてレンダリング結果のみを返すサービスとしています。

まとめ

2021年にもなってHTMLメールのためにレガシーな仕様に準拠するのはなかなか辛いことです。

しかし実際問題としては、レガシーなメールクライアントは利用されていますし、そうしたクライアントでも表示できるHTMLメールを送信したいというニーズも当面存在し続けるのだろうと思っています。

HTMLメールを実装される際のご参考になれば幸いです。
またよりよいプラクティスをお持ちの方いれば、ぜひ教えてください!

この記事が気に入ったらサポートをしてみませんか?