📫

HTMLメール制作で絶対知っておくべき落とし穴まとめ(Mailtrapで検証)

に公開

最近、HTMLメールの表示崩れを直す機会がありました。

元のレイアウトはdivタグベースかつflexレイアウトで組まれていましたが、
最終的にtableレイアウトへと全面的に組み直しました。

※初めてHTMLメールに関する対応を行いましたが、Webページを作る際とは随分と勝手が違うなと感じました…
(シーラカンスかよと思いました。)

そんなわけで、今回はHTMLメールを作る際の注意点を簡単にまとめたいと思います。

HTMLメールの崩れを修正する方法

私は以下の流れで修正を行いました。

  1. ローカルでは Mailtrap に向けて送信して確認する
  2. 実際にテスト環境で各メールクライアントに向けて送信して確認する

Mailtrapに向けて送信して確認する方法

簡単に確認できるソースコードを提供します。

※node.jsを用いる例です。もちろん他の好きな言語やフレームワークを使っても大丈夫です。
実際の運用では環境変数などにMailtrapの情報を持たせるのがおすすめですが、ここでは分かりやすさのためにコードに直接書いています。

index.js
const nodemailer = require("nodemailer");

// Mailtrapの「Email Testing」 > Inbox > Integrationに表示される値を使う
const transporter = nodemailer.createTransport({
  host: "sandbox.smtp.mailtrap.io",
  port: 2525, // Mailtrap Email Testingのデフォルトポート
  auth: {
    user: "あなたのUsername", // ここを書き換え
    pass: "あなたのPassword", // ここを書き換え
  },
});

// HTMLメールのテスト用コンテンツ
const html = `
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8" />
  <title>HTMLメール検証</title>
  <style>
    .flex-header {
      display: flex;
      justify-content: space-between;
      padding: 16px;
      margin: 16px 0;
      background-image: linear-gradient(45deg, #2196f3, #e91e63);
      color: #ffffff;
    }
  </style>
</head>
<body style="margin:0; padding:0;">

  <h1 style="font-size:20px; margin:16px;">HTMLメールのCSS検証サンプル</h1>

  <!-- flex依存で崩れやすい部分 -->
  <div class="flex-header">
    <div>左側(flex)</div>
    <div>右側(flex)</div>
  </div>

  <!-- table レイアウトで安全な部分 -->
  <table width="100%" cellpadding="0" cellspacing="0" border="0" style="margin-top:16px;">
    <tr>
      <td align="left" style="font-size:14px; padding:4px 16px;">
        左側(tableレイアウト)
      </td>
      <td align="right" style="font-size:14px; padding:4px 16px;">
        右側(tableレイアウト)
      </td>
    </tr>
  </table>

  <p style="font-size:14px; line-height:1.6; margin:16px;">
    このメールは、HTMLメールで flex / margin / background-image などが
    各クライアントでどう表示されるか確認するためのテストメールです。
  </p>

</body>
</html>
`;

async function main() {
  try {
    const info = await transporter.sendMail({
      from: '"HTML Mail Tester" <test@example.com>',
      to: "test@example.com", // MailtrapのInboxなら何でもOK
      subject: "HTMLメールのCSS検証サンプル",
      html,
    });

    console.log("メール送信完了:", info.messageId);
  } catch (err) {
    console.error("送信エラー:", err);
  }
}

main();

※以下のコマンドで実行できます。

node index.js

Mailtrap側の準備

以下のように準備してください。

  1. 未登録の場合はMailtrapアカウントを作成※GoogleアカウントやGithubアカウントで簡単に登録できます。
  2. 「Email Testing」のInboxをひとつ作成(デフォルトのままでもOK)
  3. 前の手順で作成したSandboxを開く
  4. IntegrationタブにUsernamePasswordがあるので、それをコピーして先述のコードに貼り付け

HTMLメールを作成する際の注意点

ここからは、上記の画像のようにHTMLメールをMailtrap上で参照すると表示されるHTML Checkタブの表示を見ながら、HTMLメールを作成する際の注意点をまとめたいと思います。
(サンプルコードを実行すると、上記の画像のような結果になりました。)

HTML Checkタブの動きとしては、HTMLに含まれているタグに紐づく注意点を表示するものです。
以下の点に留意する必要があります。

  • タグが含まれていれば警告を表示するので、実際には問題がなくても警告が表示される場合があります。(例えば、displayがインラインでCSSに指定されている場合、flexを用いていなくてもflexに関連する注意点が表示されます。)
  • 日本ではあまり使われていないメーラーに関する警告や、古いバージョンのメーラーに関する警告も出すので、どこまで対応するのか事前に要件を確認する必要があります。

bodyタグはdivタグに置換される

警告の英文の通り、主要なメールクライアントでは <body> タグが
安全な属性だけを持つ独自の<div>に置き換えられます。

そのため<body>にインラインスタイルを指定していた場合でも、
各メールクライアントでサポートされていないスタイルは自動的に削除され、
意図した見た目にならない可能性があります。

※どのスタイルがサポートされていないかは後述します。

justify-contentは多くのメールクライアントでサポートされていない

justify-contentは、flexboxを前提としたプロパティのため、HTMLメールではほとんどの
メールクライアントでサポートされていません。

画像にある通り、GmailやOutlookなど主要クライアントは赤アイコン=非対応で、
Notesを見ると、2020年時点では完全に非対応、2023年以降の一部バージョンで部分的に対応し始めたという記載があります。

実務的には、justify-contentは現在でも広く非対応と考えるべきで、
HTMLメールでは使用しないのが安全です。

※サンプルコードにも書いている通り、tableレイアウトを用いましょう。

スタイルはインラインで書くべき

画像の警告が示す通り、HTMLメールにおける<style>タグは
メールクライアントによっては
削除されたり、無視されたり、位置によって動作が壊れたりします。

特にGmailやOutlookは<body>内の<style>を削除したり、
HTML構造を書き換えて<head>そのものを消すこともあるため、
スタイルが反映される保証がありません。

2020年のバージョンでは非対応、2023年には一部対応、
その後のバージョンでは再び非対応というように、挙動が非常に不安定です。

実務では<style>を使用せず、すべてインラインCSSで記述するのが安全です。

display: flexはほぼ使えない

display:flexは、HTMLメールではほとんどのメールクライアントで非対応です。

Notesを見ると、2020年のバージョンでは非対応、2020〜2021の一部バージョンで
一時的にサポートされたものの、その後また非対応に戻るなど、
クライアントやバージョンによって挙動が安定しません。

また、Gmailでは、Gmailアカウント以外で受信した場合は動かないなど、
同じアプリ内でも挙動が異なるケースがあります。

実務的には、display:flexはHTMLメールでは広く非対応と考えるべきで、
レイアウトはすべてtableベースで構築するのが安全です。

background-imageもほぼ使えない

background-image は、HTMLメールではほとんどのメールクライアントで非対応または部分対応で、
非常に不安定なプロパティです。

特にGmailでは、background-image: url(...)を書くと安全性の観点から
style 属性全体が削除される場合があり、背景画像だけでなく他のスタイルも
まとめて消えてしまうことがあります。

またWindows版OutlookではWeb標準のCSSが使えず、VMLという
Microsoft独自の記法で背景画像を指定する必要があります。

Yahoo!Mailでは複数画像の指定が正しくパースされず、画像URLを
クォートで囲まないと読み込めないなど、クライアントごとに仕様が
まったく異なるため、安定した背景画像の表示は困難です。

実務では、HTMLメールでbackground-imageは「原則使わない」、
背景色(background-color)や画像そのものを<img>として配置する方式が推奨されます。

displayを使った近代的なレイアウトは使えない

displayプロパティは、HTMLメールでは多くの値が非対応または部分対応で、
特に flex/grid/flow-root/contents/inline-flexなどの近代的な値は
ほぼすべてのメールクライアントで無視されます。

Outlookではdisplay:none以外の値が効かず、display:noneでさえ
入れ子のtableに継承されないバグがあります。
Yahoo!Mailでも大量のdisplay値がサポートされていません。

このようにdisplayを使ったレイアウトはHTMLメールでは実質不可能であり、
レイアウトはすべてtable要素で組むことが推奨されています。

lang属性を要素単位で指定しない

lang属性は、本来アクセシビリティや文章の読み上げ処理のために
HTMLで使用される属性ですが、HTMLメールではクライアントによって
対応状況が大きく異なります。

特にYahoo!Mailでは<td lang="...">のような要素単位の
lang属性が無視される場合があり、細かいレベルでの言語指定は反映されません。

またNotesの通り、2020年のバージョンでは対応していたものが
2021年のバージョンで非対応になるなど、クライアントやバージョンに
よって挙動が安定していません。

実務上は、HTMLメールでlang属性を厳密に使う必要性は低く、
文書全体を示す <html lang="ja"> 程度に留めるのが安全です。

marginの挙動が不安定

marginはHTMLメールでは非常に扱いにくく、クライアントごとに
対応が大きく異なります。Notesの通り、負のmargin(negative margin)は
GmailやOutlookでは無視され、margin: autoもOutlook Windowsが
非対応のため中央寄せができません。

さらにOutlookでは、marginbackground-colorを組み合わせると
背景色がmargin領域にまで広がって描画されるバグがあり、クライアント間で
大きな見た目の差が生じます。また<span><body>のmarginが
無視されるクライアントも存在します。

このようにmarginはHTMLメールでは非常に不安定なため、余白は
paddingを使用し、レイアウトはtableベースで組むのが安全です。

Outlookでline-heightの挙動が不安定

HTMLメールではline-heightの挙動が特にOutlookで不安定です。

Notesの通り、Outlook(Windows版)はline-height: 20px1.4emといった
単位付きの指定が正しく反映されず、行間が変わってしまうバグがあります。
こうしたケースではmso-line-height-rule: exactly;を併用することで、
Outlookでも安定した行間が得られます。

また、一部クライアントではline-height: normalがサポートされていなかったり、
実際の表示が非常にまちまちになるため、HTMLメールではline-heightは
1.5のように数値で指定するのが最も安全です。

Outlookではpaddingの挙動が制限される

HTMLメールではpaddingの挙動がOutlook(Windows版)で大きく制限されます。

Notesの通り、Outlookはpaddingを「table セル(<td>)に対してのみ」
サポートしており、<div><p>などに指定したpaddingは基本的に無視されます。

さらに、縦方向のpaddingにバグがあり、同じ行にある複数の<td>に異なる
padding-toppadding-bottomを設定した場合、Outlookでは
「行内で最も大きいpaddingに強制的に統一される」という問題があります。

このため、HTMLメールではpaddingは必ず<td>に記述し、
上下方向のpaddingを行内で揃えるか、必要に応じて行を分割する設計が必要です。

width属性のOutlookでの挙動に注意

HTMLメールでは、width属性の挙動がOutlook(Windows版)で特に不安定です。

Notesの通り、<img width="100%">のようなパーセント指定は
「親要素ではなく画像ファイル自身の幅」を基準に計算されるバグがあり、
Outlookでは画像が思わぬ大きさで表示されてしまいます。

また、width属性で指定されたサイズはWindowsのDPIスケール
(120dpi/125% 表示など)に追従せず、画像だけが拡大縮小されない問題もあります。

このため、HTMLメールではwidthは属性だけに依存せず、
style="width:600px;"のようにCSSと併用したり、
ラップ用のtableを活用してレスポンシブにするのが安全です。

Discussion