メールの HTML を React + TypeScript + TailwindCSS で書く

2 min read読了の目安(約2000字

React コンポーネントをサーバーサイドレンダリングすることで、メールの HTML を React で書くことができる。
フロントエンドで React を使っている場合、一貫性のある技術スタックになって嬉しい。また TypeScript であれば型安全にメールがかけるので、なお嬉しい。

基本的には、下記のようにすれば、静的な HTML が吐き出せる。これを Mailgun などに送れば OK。

import React from 'react'
import ReactDOMServer from 'react-dom/server'

const Email = () => (
  <html>
    <body>
      <div>
        <p>Hello, email!</p>
      </div>
    </body>
  </html>
)

const html = ReactDOMServer.renderToStaticMarkup(element)

CSS は <head /> の中に書いてしまうのが一番簡単。また Juice を使ってインライン化すれば、 Outlook などにも対応しやすい。

import juice from 'juice'
import React from 'react'
import ReactDOMServer from 'react-dom/server'

const Email = () => (
  <html>
    <head>
      <style>{`
        .button {
	  padding: 4px;
	  background-color: #333;
	  color: #fff;
	}
      `}</style>
    </head>
    <body>
      <div>
        <p>Hello, email!</p>
	<button className="button">LEARN MORE</button>
      </div>
    </body>
  </html>
)

const staticMarkup = ReactDOMServer.renderToStaticMarkup(element)
const html = juice(staticMarkup)

このままでも良いのだが、 TailwindCSS をフロントエンドで使っている場合、同じ要領で書けると更に嬉しい。単純に <style> 内に TailwindCSS を全て入れても良いのだが、せっかくなので tailwind-rn というライブラリを使ってみた。

もともとは React Native 用のライブラリだが、やっていることは TailwindCSS のクラスを React が扱える style のオブジェクトに変換しているだけなので、いい感じに使える。普通に React Native で TailwindCSS 使いたい時にもお薦め。

https://github.com/vadimdemedes/tailwind-rn
import React from 'react'
import ReactDOMServer from 'react-dom/server'
import tailwind from 'tailwind-rn'

const Email = () => (
  <html>
    <body>
      <div>
        <p>Hello, email!</p>
	<button style={tailwind('p-1 bg-gray-800 text-white')}>
	  LEARN MORE
	</button>
      </div>
    </body>
  </html>
)

const html = ReactDOMServer.renderToStaticMarkup(element)

tailwind-rn はインラインで CSS を記述するようになるので、 TailwindCSS で完結させれば Juice が必要なくなったのも嬉しい。

注意点としては text-lg 等のスタイルを利用すると、 line-height がおかしなことになる。結局 Juice でグローバルに * { line-height: 1.6 !important } というスタイルを当てているが、もっと良い解決策がありそう。単位を必ず px にするとか。