業務システムや通知メールで、
- Markdown で本文を書く
- サーバー側で HTML に変換してメール送信する
という構成を採用している方は多いと思います。
しかし、
管理画面や他のメーラーでは問題ないのに Gmail だけ表示が崩れる
という現象に遭遇したことはありませんか?
この記事は、Markdown でメール本文を書き、サーバー側で HTML 変換して送信しているエンジニア向けに、
Markdown → HTML → Gmail の流れで発生するスタイル崩れの原因と、
実務で有効だった対策を整理します。
結論(先に)
- Gmail は 一部の HTML タグのスタイルを自動的に上書きする
-
<p>/<strong>/<em>などは特に影響を受けやすい - CSS はほぼ無効、インラインスタイル前提で設計する必要がある
- Markdown の出力 HTML をそのまま使うのは危険
よくある構成
多くの現場で、以下のような流れになっています。
Markdown
↓(パーサー)
HTML
↓(メール送信)
Gmail / Outlook / Apple Mail
Markdown パーサーは次のような HTML を生成します。
<p>本文テキスト <strong>強調</strong></p>
一見すると正しく、管理画面のプレビューでも問題ありません。
問題:Gmail による「スタイルの標準化」
Gmail は セキュリティ・可読性の観点から、
HTML メールに対して独自の処理を行います。
Gmail が行う主な処理
-
<style>タグの削除・無視 - 一部 CSS プロパティの無効化
- HTML タグごとの デフォルトスタイル強制
その結果、以下のようなことが起こります。
-
<p>のmarginが勝手に付く / 消える -
<strong>のfont-weightが意図しない値になる - フォントサイズが Gmail 標準に引き戻される
※ これらの挙動は 予告なく変更されることがあり、「以前は大丈夫だった」が普通に起こります。
具体例:管理画面では正常、Gmail では崩れる
管理画面(期待通り)
- フォントサイズ:14px
- 行間:1.6
- 太字:少し強調
Gmail
- フォントサイズが 16px 相当に拡大
-
<p>の上下に余白が入る - 太字が想定より強くなる
原因は、Markdown パーサーが生成した素の HTML タグが Gmail の上書き対象になっているためです。
対策①:インラインスタイルを前提にする(最重要)
Gmail で最も安定するのは インラインスタイル です。
❌ NG(ほぼ無視される)
<style>
p { font-size:14px; line-height:1.6; }
</style>
⭕ OK(比較的安全)
<p style="font-size:14px; line-height:1.6; margin:0;">
本文テキスト
</p>
対策②:Markdown 出力 HTML を後処理する
Markdown → HTML 変換後、そのまま送らないのがポイントです。
やること
-
<p>にstyleを強制付与 -
<strong>/<em>にもfont-weight/font-styleを明示 - 不要なタグは
<span>に置き換える
例(Laravel / PHP イメージ)
$html = convertMarkdownToHtml($markdown);
$html = str_replace(
'<p>',
'<p style="font-size:14px; line-height:1.6; margin:0;">',
$html
);
※ 正規表現ではなく DOM パーサーで安全に処理するのが理想です。
対策③:メール用 HTML と割り切る
Web 用 HTML の常識は メールでは通用しません。
メール HTML の割り切り
- CSS 設計は最小限
-
tableレイアウトも許容 - モダン CSS は使わない
Markdown は 入力補助ツールと割り切り、
最終形は「メール特化 HTML」に変換するのが現実解です。
対策④:HTMLメール用の HTML クリーンアップ
Markdown → HTML 変換後に、
「HTMLメールとして安全な状態に整える工程」 を必ず挟みます。
ここで重要なのは、
- Web 用 HTML を期待しない
- Gmail に解釈されやすい形に寄せる
- 表示が変わりやすい要素を明示的に固定する
という考え方です。
Markdown はあくまで「入力を楽にするための記法」であり、
最終的に送信するのは メール特化 HTML です。
クリーンアップで行うこと
最低限、以下のような処理を行うと Gmail での表示が安定します。
-
<p>にfont-size / line-height / marginを明示 -
<strong>にfont-weightを明示 -
<em>にfont-styleを明示 -
<style>/<script>タグの削除 - Gmail で解釈が不安定な属性の除去
特に <p> / <strong> / <em> は
Gmail 側でスタイルを上書きされやすいタグなので、
意図した見た目をインラインスタイルで固定します。
実装イメージ(例)
以下は PHP / Laravel を想定した一例です。
言語やフレームワークが違っても、考え方は同じです。
libxml_use_internal_errors(true);
$dom = new DOMDocument('1.0', 'UTF-8');
$dom->loadHTML(
mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8'),
LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD
);
$xpath = new DOMXPath($dom);
// <p>
foreach ($xpath->query('//p') as $p) {
$p->setAttribute(
'style',
'font-size:14px; line-height:1.6; margin:0 0 12px 0;'
);
}
// <strong>
foreach ($xpath->query('//strong') as $strong) {
$strong->setAttribute('style', 'font-weight:600;');
}
// <em>
foreach ($xpath->query('//em') as $em) {
$em->setAttribute('style', 'font-style:italic;');
}
// <style> / <script> 削除
foreach ($xpath->query('//style | //script') as $node) {
$node->parentNode->removeChild($node);
}
$html = $dom->saveHTML();
※ 正規表現ではなく DOM 操作で行うのが安全です。
なぜクリーンアップ工程が必要か
Markdown パーサーの出力 HTML は、
- ブラウザ表示を前提としている
- メールクライアント特有の挙動を考慮していない
- Gmail の仕様変更に弱い
という前提があります。
そのため、
「変換結果をそのまま送る」こと自体が不安定です。
- HTMLメール用のクリーンアップを挟むことで
- 表示ルールを一箇所に集約できる
- Gmail 以外のメーラー差分にも対応しやすくなる
- 「一部のメールだけ崩れる」事故を防げる
というメリットがあります。
まとめ
- Gmail は HTML メールのスタイルを 積極的に上書きする
- Markdown パーサーの素の出力は Gmail と相性が悪い
- インラインスタイル前提 + 後処理が安定解
Markdown で書ける快適さと、
Gmail で崩れない現実的な設計の間をどう取るかが重要です。
同じ問題で悩んでいる方の参考になれば幸いです。