JavascriptでHTMLメールを送る際のテンプレートを考える(Pug、Handlebars、EJS)

テンプレートに何を使うか迷ったので比較してみます。

送りたいメール

<body>
Name さま<br>
いつも〇〇をご利用いただき、ありがとうございます。<br>
<br>
Name さまが現在保有しているポイントは、 ### ポイントです。<br>
うち ## ポイントが今月末に失効になります。<br>
<br>
詳しくは<a href="Url">こちら</a>からご確認ください。
</body>

やりたいことは、

  • Name、###、##、Urlを動的に変更したい
  • 失効予定のポイントがない場合は「うち ## ポイントが〜」の文自体をなくしたい

こんな感じです。

Pugの場合

template.pug

body
  | #{name} さま
  br
  | いつも〇〇をご利用いただき、ありがとうございます。
  br
  br
  | #{name} さまが現在保有しているポイントは、 #{current} ポイントです。
  br
  if lost
    | うち #{lost} ポイントが今月末に失効になります。
    br
  br
  | 詳しくは
  a(href=url) こちら
  | からご確認ください。

コンパイル

const pug = require('pug');

const html = pug.renderFile('template.pug', {
    name: 'hoge',
    current: 100,
    lost: 10,
    url: 'https://blare.fwhy.app'
});

結果

<body>hoge さま<br/>いつも〇〇をご利用いただき、ありがとうございます。<br/><br/>hoge さまが現在保有しているポイントは、 100 ポイントです。<br/>うち 10 ポイントが今月末に失効になります。<br/><br/>詳しくは<a href="https://blare.fwhy.app">こちら</a>からご確認ください。</body>

Handlebarsの場合

template.hbs

<body>
    {{name}} さま<br>
    いつも〇〇をご利用いただき、ありがとうございます。<br>
    <br>
    {{name}} さまが現在保有しているポイントは、 {{current}} ポイントです。<br>
    {{#if lost}}
    うち {{lost}} ポイントが今月末に失効になります。<br>
    {{/if}}
    <br>
    詳しくは<a href="{{url}}">こちら</a>からご確認ください。
</body>

コンパイル

const fs = require('fs');
const Handlebars = require('handlebars');

const html = Handlebars.compile(fs.readFileSync('template.hbs', 'utf-8'))({
    name: 'hoge',
    current: 100,
    lost: 10,
    url: 'https://blare.fwhy.app'
});

結果

<body>
    hoge さま<br>
    いつも〇〇をご利用いただき、ありがとうございます。<br>
    <br>
    hoge さまが現在保有しているポイントは、 100 ポイントです。<br>
    うち 10 ポイントが今月末に失効になります。<br>
    <br>
    詳しくは<a href="https://blare.fwhy.app">こちら</a>からご確認ください。
</body>

EJSの場合

template.ejs

<body>
    <%= name %> さま<br>
    いつも〇〇をご利用いただき、ありがとうございます。<br>
    <br>
    <%= name %> さまが現在保有しているポイントは、 <%= current %> ポイントです。<br>
    <% if (lost) { -%>
    うち <%= lost %> ポイントが今月末に失効になります。<br>
    <% } %>
    <br>
    詳しくは<a href="<%= url %>">こちら</a>からご確認ください。
</body>

コンパイル

const ejs = require('ejs');

const html = await ejs.renderFile('template.ejs', {
    name: 'hoge',
    current: 100,
    lost: 10,
    url: 'https://blare.fwhy.app'
});

結果

<body>
    hoge さま<br>
    いつも〇〇をご利用いただき、ありがとうございます。<br>
    <br>
    hoge さまが現在保有しているポイントは、 100 ポイントです。<br>
    うち 10 ポイントが今月末に失効になります。<br>
    <br>
    詳しくは<a href="https://blare.fwhy.app">こちら</a>からご確認ください。
</body>

総評

Pugはコンパイル結果に改行が含まれていないので多少はメール容量の削減ができそうです。
が、いかんせんテンプレートを書くのが面倒すぎます。
Vue.jsで使用するときみたいに全行を<div><p>タグで囲むようにすればよいのでしょうが、 今回のように<body>に平文で書きつつ改行は適宜<br>で行うような場合には不向きなようです。

HandlebarsとEJSはテンプレートも出力されるHTMLもさほど変わりないですが、結論から言うとEJSのほうが良さそうです。
上記の例には出しませんでしたがHandlebarsは別ファイルの取り込みが苦手なようです(できなくはないようですが)。
他のメールも送る場合、署名等の共通な箇所は別ファイルにしたくなると思うので、簡単に取り込みできるEJSのほが良いと思います。
またメール送信にSendGridを使う場合、SendGrid側のテンプレートがHandlebarsの構文と被るのでEJSのほうが楽です。

あと、人によっては「<% %>は通常のHTMLタグと被るのが嫌だ」というのがあるかもしれませんが、安心してください変更できます。 Handlebarsは変更できないので「{{ }}がLaravelのBladeテンプレートと被るから嫌だ」といっても我慢してください。