0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

レスポンシブHTMLメールの作り方とメーラー互換性

0
Posted at

Webではきれいに表示できるHTMLが、メールにすると途端に崩れる——HTMLメールを作ったことがある方なら一度は経験があると思います。原因は、メールクライアント(メーラー)ごとにレンダリングの仕様がバラバラで、しかも「普通のWeb開発で使える書き方」が通用しないからです。

本記事では、HTMLメールがなぜ崩れるのかという前提から、テーブルレイアウトの基本・レスポンシブ化・Outlook/Gmailなど主要メーラー対策・ダークモード対応までを実コード付きで解説し、最後に作ったHTMLをblastengineで送るところまでつなげます。

なぜHTMLメールは「普通のWeb」で作れないのか

ブラウザのレンダリングエンジンが数種類に収束しているWebと違い、メーラーは受信側の環境によってまったく異なるエンジンでHTMLを解釈します。特に厄介なのがWindowsのデスクトップOutlookで、これはブラウザではなくWordのレンダリングエンジンでHTMLを描画します。marginbackground-imageflexgrid といった現代的なCSSの多くが効きません。

メーラー 描画の傾向 注意点
Outlook(Windowsデスクトップ) Wordエンジン margin・flex・background-image非対応、要VML
Gmail(Web/アプリ) 独自 <style>は一部のみ反映、約102KBで本文クリップ(目安)
Apple Mail / iOS Mail WebKit 比較的素直、電話番号や日付を自動リンク
Yahoo!メール・各種Webメール 独自 クラス名のリネーム等、挙動に差

このため、HTMLメールでは次のものは基本的に避けます。

  • 外部CSSファイル(<link>)や <style> への過度な依存(Gmailなどで落とされる)
  • flexbox / grid / position / float(一部メーラーで崩れる)
  • JavaScript(ほぼすべてのメーラーで無効)

代わりに、テーブルレイアウト+インラインCSSという、一見すると古風な書き方が最も安全です。

基本構造:テーブルレイアウト+インラインCSS

レイアウトは div ではなく table で組みます。横幅は本文を 600px 程度に固定し、外側のテーブルで中央寄せにするのが定番です。装飾のないテーブルには role="presentation" を付け、スクリーンリーダーに表として読まれないようにします。

<!DOCTYPE html>
<html lang="ja" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <title>お知らせ</title>
</head>
<body style="margin:0; padding:0; background-color:#f4f4f4;">
  <!-- 外側テーブル:背景と中央寄せ -->
  <table role="presentation" width="100%" cellpadding="0" cellspacing="0" border="0">
    <tr>
      <td align="center" style="padding:24px 0;">
        <!-- 本文テーブル:600px固定 -->
        <table role="presentation" class="container" width="600" cellpadding="0" cellspacing="0" border="0"
               style="width:600px; max-width:600px; background-color:#ffffff;">
          <tr>
            <td style="padding:24px; font-family:'Hiragino Sans','Yu Gothic',sans-serif; font-size:16px; color:#333333; line-height:1.6;">
              本文がここに入ります。
            </td>
          </tr>
        </table>
      </td>
    </tr>
  </table>
</body>
</html>

このコードでの注目点は次のとおりです。

  • CSSは原則インライン(style 属性) で書きます。Gmailは <head> 内の <style> を一部しか解釈しないため、見た目を決めるスタイルはタグに直接書くのが安全です
  • cellpadding="0" cellspacing="0" border="0" をテーブルに付け、意図しない余白や枠線を消します
  • フォントは font-family で指定しますが、メーラーが対応しない場合に備えてシステムフォントを並べておきます

レスポンシブ化:メディアクエリで1カラムに

スマホでの表示を整えるには、max-width で最大幅を抑えつつ、メディアクエリで狭い画面のときにレイアウトを1カラムへ畳みます。メディアクエリ自体は <style> に書きますが、インラインCSSのフォールバックを前提に、メディアクエリは「上書き」として使うのがコツです。

<style>
  @media screen and (max-width: 600px) {
    .container { width: 100% !important; }
    .col       { display: block !important; width: 100% !important; }
    .px        { padding-left: 16px !important; padding-right: 16px !important; }
    .fs        { font-size: 15px !important; }
    img        { width: 100% !important; height: auto !important; }
  }
</style>

2カラムを縦並びに畳む場合は、各カラムの tdclass="col" にしておき、狭幅時に display:block; width:100% で縦積みにします。

<table role="presentation" width="100%" cellpadding="0" cellspacing="0" border="0">
  <tr>
    <td class="col" width="300" valign="top" style="padding:8px;">左カラム</td>
    <td class="col" width="300" valign="top" style="padding:8px;">右カラム</td>
  </tr>
</table>

注目点は次のとおりです。

  • 画像は width:100%; height:auto; display:block; で可変にし、td の幅に追従させます
  • !important を付けるのは、インラインCSSよりメディアクエリを優先させるためです
  • Outlookはメディアクエリを解釈しないので、width="600" のようなHTML属性での幅指定も併用しておくと崩れにくくなります

余白はmarginではなくスペーサーで作る

WebではおなじみのCSS margin ですが、HTMLメールでは——特にOutlookでは——無視されることが多く、要素どうしが密着してしまいます。HTMLメールでは余白も「構造」で作るのが安全で、方法は次の2つです。

  1. tdpadding で内側に余白を取る
  2. 高さだけを持たせた空の行(スペーサー)をセクションの間に挟む

スペーサー行は、空セルがメーラーによって潰れないように line-heightfont-size:0 を添えるのがポイントです。

<!-- セクション間に挟む高さ24pxのスペーサー -->
<tr>
  <td height="24" style="height:24px; line-height:24px; font-size:0;">&nbsp;</td>
</tr>

注目点は次のとおりです。

  • font-size:0line-height を指定しないと、メーラーによっては行に余分な高さがついて余白がずれます
  • 空セルが詰められないよう、中身に &nbsp; を入れておきます
  • 上下左右の余白を細かく調整したいときは tdpadding を優先し、セクションどうしの分離だけスペーサーで作ると管理しやすくなります

主要メーラー対策の勘所

Outlook(Windowsデスクトップ)

最大の難所です。margin が効かないので余白は tdpadding で作り、ボタンの角丸や背景はVML(Vector Markup Language)で補います。下は「どのメーラーでも崩れないボタン」の定番パターンです。<!--[if mso]> はOutlookだけが解釈する条件分岐コメントです。

<!--[if mso]>
<v:roundrect xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="urn:schemas-microsoft-com:office:word"
  href="https://example.com" style="height:44px; v-text-anchor:middle; width:220px;" arcsize="10%"
  strokecolor="#1a73e8" fillcolor="#1a73e8">
  <w:anchorlock/>
  <center style="color:#ffffff; font-family:sans-serif; font-size:16px; font-weight:bold;">詳しく見る</center>
</v:roundrect>
<![endif]-->
<!--[if !mso]><!-->
<a href="https://example.com"
   style="background-color:#1a73e8; color:#ffffff; display:inline-block;
          padding:12px 24px; border-radius:4px; text-decoration:none;
          font-family:sans-serif; font-size:16px; font-weight:bold;">詳しく見る</a>
<!--<![endif]-->

Outlookには上のVML版、それ以外には通常の <a> ボタンが表示されます。

Outlookで背景画像を表示したい場合も、CSSの background-image は効かないためVMLで補います。背景の上にテキストを重ねる定番パターンは次のとおりです。

<!--[if mso]>
<v:rect xmlns:v="urn:schemas-microsoft-com:vml" fill="true" stroke="false" style="width:600px; height:300px;">
  <v:fill type="frame" src="https://example.com/hero.jpg" color="#1a73e8" />
  <v:textbox inset="0,0,0,0">
<![endif]-->
<div style="background-image:url('https://example.com/hero.jpg'); background-size:cover; width:600px; height:300px;">
  <table role="presentation" width="100%" height="300" cellpadding="0" cellspacing="0" border="0">
    <tr><td align="center" style="color:#ffffff; font-size:24px; font-weight:bold;">キャンペーン開催中</td></tr>
  </table>
</div>
<!--[if mso]></v:textbox></v:rect><![endif]-->

<v:fill type="frame">color 属性は、画像が読み込めなかったときの背景色(フォールバック)になります。画像オフでも文字が読めるよう、背景色と文字色のコントラストは確保しておきます。

Gmail

<style> 内のメディアクエリは効きますが、独自にクラス名を書き換えることがあり、複雑なCSSは安定しません。インラインCSS主体で組むのが無難です。さらに知られているのが102KBクリッピングです。Gmailが公式仕様として数値を明記しているわけではありませんが、HTML本文がおよそ102KBを超えると途中で本文を切り、「メッセージ全体を表示」リンクに折りたたむ挙動が、実務上の目安として広く知られています。不要な空白やコメントを削り、本文は軽量に保ちます。

Apple Mail / iOS Mail

CSS対応は比較的素直ですが、電話番号・日付・住所を勝手にリンク化します。意図しない青リンクを防ぎたい場合は、該当箇所を <a> で包んで色を固定するなどの対処をします。

Webフォントとフォントのフォールバック

ブランドフォントを使いたい場合、Webフォントに対応しているのはApple MailやiOS Mailなど一部のメーラーに限られます。非対応のメーラーでは指定が無視され、既定フォントで表示されます。そのため、フォールバックを必ず並べるのが前提になります。

<!--[if !mso]><!-->
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+JP&display=swap" rel="stylesheet">
<!--<![endif]-->
<style>
  .body-text {
    font-family: 'Noto Sans JP', 'Hiragino Sans', 'Yu Gothic', 'Meiryo', sans-serif;
  }
</style>

注目点は次のとおりです。

  • OutlookはWebフォントに非対応で、<link> の読み込みがレイアウト崩れの引き金になることがあるため、<!--[if !mso]> で囲ってOutlookには読ませません
  • font-family の末尾は必ず sans-serif などの総称ファミリーで締め、どの環境でも破綻しないようにします
  • 本文を画像化してフォントを再現する方法は、画像オフで読めなくなる・容量が増えるためおすすめしません

ダークモード対応

スマホやMailアプリのダークモードでは、背景が暗転して文字やロゴが見えなくなることがあります。<head> でカラースキームを宣言し、メディアクエリで暗色時のスタイルを上書きします。

<meta name="color-scheme" content="light dark">
<meta name="supported-color-schemes" content="light dark">
<style>
  @media (prefers-color-scheme: dark) {
    .bg   { background-color: #1a1a1a !important; }
    .text { color: #ffffff !important; }
    .card { background-color: #2a2a2a !important; }
  }
</style>

注目点は次のとおりです。

  • ロゴは白背景前提の透過PNGだと暗色時に縁が浮きます。背景に馴染む配色か、余白を持たせた画像を用意します
  • すべてのメーラーがダークモードのCSS上書きに対応しているわけではないため、元のライト配色だけでも読める前提で作ります

画像・絵文字・プリヘッダー

受信トレイでの第一印象を決めるのがプリヘッダーテキストです。本文先頭に隠しテキストを置くと、件名の隣に表示されるプレビュー文を制御できます。

<div style="display:none; max-height:0; overflow:hidden; mso-hide:all;">
  今月の新機能と、ご利用中のお客様向けキャンペーンのお知らせです。
</div>

そのほか、画像とテキストの扱いで押さえる点は次のとおりです。

  • 画像には必ず alt を入れます。画像をオフにしている環境や、画像の読み込みに失敗したときに、altが代替テキストとして表示されます
  • 重要な情報を画像だけに載せない(画像オフだと何も伝わらない)
  • 絵文字は件名・本文で使えますが、メーラーやOSで表示が変わるため装飾の主役にはしない

完成形:基本テンプレートの全体像

ここまでの要素を組み合わせた、最小限の実用テンプレートが次のものです。ヘッダー・本文・ボタン・フッターを、スペーサーで区切りながら1カラムで構成しています。

<body style="margin:0; padding:0; background-color:#f4f4f4;">
  <div style="display:none; max-height:0; overflow:hidden; mso-hide:all;">今月のお知らせとキャンペーン情報です。</div>
  <table role="presentation" width="100%" cellpadding="0" cellspacing="0" border="0" class="bg" style="background-color:#f4f4f4;">
    <tr>
      <td align="center" style="padding:24px 0;">
        <table role="presentation" class="container" width="600" cellpadding="0" cellspacing="0" border="0" style="width:600px; max-width:600px; background-color:#ffffff;">
          <!-- ヘッダー -->
          <tr>
            <td class="px" align="center" style="padding:24px; background-color:#1a73e8; color:#ffffff; font-size:20px; font-weight:bold;">サービス名</td>
          </tr>
          <!-- 本文 -->
          <tr>
            <td class="px text" style="padding:24px; font-family:'Hiragino Sans',sans-serif; font-size:16px; color:#333333; line-height:1.7;">
              いつもご利用ありがとうございます。今月の新機能をご案内します。
            </td>
          </tr>
          <!-- ボタン -->
          <tr>
            <td align="center" style="padding:0 24px 24px;">
              <a href="https://example.com" style="background-color:#1a73e8; color:#ffffff; display:inline-block; padding:12px 28px; border-radius:4px; text-decoration:none; font-weight:bold;">詳しく見る</a>
            </td>
          </tr>
          <!-- スペーサー -->
          <tr><td height="8" style="height:8px; line-height:8px; font-size:0;">&nbsp;</td></tr>
          <!-- フッター -->
          <tr>
            <td class="px" align="center" style="padding:16px 24px; background-color:#f0f0f0; font-size:12px; color:#888888;">
              配信停止は<a href="https://example.com/unsubscribe" style="color:#888888;">こちら</a>
            </td>
          </tr>
        </table>
      </td>
    </tr>
  </table>
</body>

このテンプレートに、前述のメディアクエリ・ダークモード・MSO条件分岐を必要に応じて足していけば、主要メーラーで崩れにくいメールの土台になります。

blastengineで送る

作ったHTMLは、blastengineの送信時に html フィールド に渡すだけです。HTMLを表示できない環境向けに、text(プレーンテキスト版)も必ず併記します。送信処理そのものは別記事「Spring BootからblastengineのJava SDKで送る」で解説していますが、HTMLの差し込み部分だけ抜粋すると次のようになります。

BETransaction tx = new BETransaction();
tx.subject = "今月のお知らせ";
tx.text = "HTMLを表示できない環境向けのテキスト版です。詳しくはWebでご確認ください。";
tx.html = loadHtmlTemplate();   // 上で作成したHTMLを読み込む
tx.setFrom(new BEMailAddress("info@example.com", "お知らせ"));
tx.addTo("user@example.jp");
tx.send();

注意点は次のとおりです。

よくある崩れと対処

実装中に遭遇しやすい崩れと、その原因・対処をまとめます。

症状 よくある原因 対処
Outlookだけ余白が消える margin を使っている padding かスペーサー行に変える
Outlookで画像の下に隙間 画像がインライン要素扱い imgdisplay:block を指定
Gmailで途中から表示されない 本文が102KB超 不要な空白・コメントを削る
スマホで横スクロールが出る 固定幅が画面より広い max-width とメディアクエリで100%化
リンクが勝手に青くなる iOSの自動リンク 該当文字を <a> で包み色を固定
背景が黒くて文字が読めない ダークモードの反転 カラースキーム宣言とメディアクエリ

崩れたときは「どのメーラーで」「ライト/ダークどちらで」起きるかを切り分けると、原因の見当がつけやすくなります。

テストとチェックリスト

HTMLメールは「実機で見るまで分からない」のが鉄則です。最低限、次の環境で確認します。

  • Outlook(Windowsデスクトップ)/Gmail(Web・モバイルアプリ)/Apple Mail(iOS)
  • ライトモードとダークモードの両方
  • 画像オフの状態でも意味が通るか
  • 本文サイズが102KB未満か(Gmailのクリッピング回避)

LitmusやEmail on Acidのようなプレビューサービスを使うと、多数のメーラーでの表示を一括確認できます。本番配信の前に、blastengineのテスト送信で自分宛に1通送り、実機で目視するのが確実です。

まとめ

  • HTMLメールはメーラーごとに描画仕様が異なり、特にOutlookはWordエンジンのため「普通のWeb」の書き方が通用しません
  • レイアウトはテーブル+インラインCSS、レスポンシブはメディアクエリでの上書きが基本です
  • OutlookはMSO条件分岐+VML、Gmailはインライン主体+102KB制限、ダークモードはカラースキーム宣言+メディアクエリで対応します
  • 完成したHTMLはblastengineの html フィールドに渡し、text 版とセットで送ります。UTF-8の統一と実機テストを忘れずに

見た目の作り込みは到達後の成果(開封後の読みやすさ・クリック)に直結します。まずはテーブル骨格の1カラムから組み、メーラーごとの対策を1つずつ足していくのがおすすめです。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?