邮件客户端剥离head/style标签并过滤class,仅支持内联style;juice可自动内联但需预处理响应式样式、保留!important、手动读入CSS;最终须用table布局、显式vertical-align、字体兜底,并经真实客户端测试。

为什么邮件客户端不认
因为绝大多数邮件客户端(Gmail、Outlook、Apple Mail)会直接剥离 <head> 和 <style> 标签,甚至过滤掉 class 属性。不是它们“不支持CSS”,而是主动限制——防止样式干扰客户端自身UI或被滥用于追踪。所以外联、嵌入式样式一律失效,只剩内联 style 属性能活下来。
手动写style属性太容易出错
人眼很难保证每个 <td>、<p>、<div> 都带对字体、颜色、边距,尤其嵌套表格时 margin/padding 会被 Outlook 解析成奇怪高度。常见错误包括:
- 漏写
!important(某些 Outlook 版本要求它才生效) - 用
rem或em单位(只认px和百分比) - 写了
display: flex(Gmail Android、Outlook.com 全面不支持) - 给
<table>设max-width(部分客户端忽略)
真实项目里,靠手写内联样式维护 5 个以上模板,两周后自己都看不懂哪段 style 对应哪块结构。
用juice自动内联但要注意三件事
juice 是 Node.js 下最稳的内联工具,但它默认行为在邮件场景下有坑:
立即学习“前端免费学习笔记(深入)”;
- 不会处理
@media查询(得提前用postcss-preset-env把响应式规则转成桌面/移动端两套独立样式再喂给 juice) - 遇到
!important会原样保留,但 Outlook 某些版本只认!important,所以建议所有关键样式都加它 - 不解析
<link rel="stylesheet">,必须先用fs.readFileSync把 CSS 内容读进来,再传给juice.inlineContent(html, css)
示例关键调用:
const juice = require('juice');
const html = fs.readFileSync('template.html', 'utf8');
const css = fs.readFileSync('email.css', 'utf8');
const inlined = juice.inlineContent(html, css, {
preserveImportant: true,
webResources: { images: false } // 邮件里图片走绝对URL,别让juice瞎转base64
});
内联后还得过Outlook和Gmail的校验关
内联只是第一步。Outlook(尤其是 Windows 桌面版)会把 <div> 强制替换成 <span>,导致块级布局崩溃;Gmail 会删掉空格和换行,让多行 style 值粘连。所以最终检查点只有三个:
- 所有容器必须用
<table>+<tr>+<td>,别信“现代HTML” - 每个
<td>必须显式设style="vertical-align: top;",否则 Outlook 默认居中挤变形 - 字体栈末尾加
sans-serif或serif(Gmail 会忽略没兜底的字体名)
发测试邮件前,用 htmlemail.io 或 Mailchimp Inbox Preview 看真实渲染,别只信本地浏览器。
真正麻烦的不是怎么内联,而是内联之后还要为每个客户端补一堆条件注释、重复样式、降级结构——这些没法自动化,只能靠经验填坑。








