Webではきれいに表示できるHTMLが、メールにすると途端に崩れる——HTMLメールを作ったことがある方なら一度は経験があると思います。原因は、メールクライアント(メーラー)ごとにレンダリングの仕様がバラバラで、しかも「普通のWeb開発で使える書き方」が通用しないからです。
本記事では、HTMLメールがなぜ崩れるのかという前提から、テーブルレイアウトの基本・レスポンシブ化・Outlook/Gmailなど主要メーラー対策・ダークモード対応までを実コード付きで解説し、最後に作ったHTMLをblastengineで送るところまでつなげます。
なぜHTMLメールは「普通のWeb」で作れないのか
ブラウザのレンダリングエンジンが数種類に収束しているWebと違い、メーラーは受信側の環境によってまったく異なるエンジンでHTMLを解釈します。特に厄介なのがWindowsのデスクトップOutlookで、これはブラウザではなくWordのレンダリングエンジンでHTMLを描画します。margin や background-image、flex、grid といった現代的な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カラムを縦並びに畳む場合は、各カラムの td を class="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つです。
-
tdのpaddingで内側に余白を取る - 高さだけを持たせた空の行(スペーサー)をセクションの間に挟む
スペーサー行は、空セルがメーラーによって潰れないように line-height と font-size:0 を添えるのがポイントです。
<!-- セクション間に挟む高さ24pxのスペーサー -->
<tr>
<td height="24" style="height:24px; line-height:24px; font-size:0;"> </td>
</tr>
注目点は次のとおりです。
-
font-size:0とline-heightを指定しないと、メーラーによっては行に余分な高さがついて余白がずれます - 空セルが詰められないよう、中身に
を入れておきます - 上下左右の余白を細かく調整したいときは
tdのpaddingを優先し、セクションどうしの分離だけスペーサーで作ると管理しやすくなります
主要メーラー対策の勘所
Outlook(Windowsデスクトップ)
最大の難所です。margin が効かないので余白は td の padding で作り、ボタンの角丸や背景は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;"> </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();
注意点は次のとおりです。
- 日本語本文はUTF-8で扱い、HTML側の
<meta charset="UTF-8">と合わせます。ここがずれると文字化けの原因になります - 配信停止導線は別途List-Unsubscribeヘッダーで用意します(blastengineでList-Unsubscribeヘッダーを追加する方法を参照)
- 送信後の到達状況やエラーは配信レスポンスコード解読ガイドで確認できます
よくある崩れと対処
実装中に遭遇しやすい崩れと、その原因・対処をまとめます。
| 症状 | よくある原因 | 対処 |
|---|---|---|
| Outlookだけ余白が消える |
margin を使っている |
padding かスペーサー行に変える |
| Outlookで画像の下に隙間 | 画像がインライン要素扱い |
img に display: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つずつ足していくのがおすすめです。