邮件系统必须清除style标签和外部css,仅保留内联style属性,因gmail等客户端会主动剥离head/style并过滤class,仅支持内联样式;手动内联易出错且无法处理优先级、继承及伪类,需用csstoinlinestyles或juice等工具自动化转换,并经真实客户端测试验证。

大规模邮件系统里,style 标签和外部 CSS 必须被清除,只保留 style="..." 属性——这不是优化选项,是发件成功的硬门槛。
为什么不能靠手动内联?
人工给每个 <p></p>、<td>、<code><span></span> 补 style 属性,面对几百个模板、每日数百万封邮件时,错漏率高、维护成本爆炸。更关键的是:CSS 选择器优先级、继承规则、伪类(如 :hover)、媒体查询(@media)这些在邮件里全无效,手动补容易误留无用代码,反而干扰渲染。
常见错误现象:<div class="header"> 在 Outlook Desktop 中完全不生效;<code><p style="margin: 20px"></p> 在 Gmail Web 中 margin 消失;background-image 被所有主流客户端静默丢弃。
- 必须剥离所有
<style></style>和<link rel="stylesheet"> - 必须将有效样式(仅限支持属性)映射到对应 DOM 元素的
style属性中 - 必须忽略
@media、:before、display: flex等不支持特性
PHP 场景下用 CssToInlineStyles 的真实约束
CssToInlineStyles 是目前 PHP 生态最稳的方案,但它不是“一键万能”。它的 convert() 方法默认不处理 <style></style> 标签里的 CSS,需显式提取;也不自动加载 <link> 引用的外部文件。
实操建议:
- 先用
DOMDocument提取 HTML 中的<style></style>内容,再传给convert($html, $css) - 外部 CSS 文件必须用
file_get_contents()读取后拼接,不能依赖自动解析 - 对含
!important的规则要谨慎——Outlook 某些版本只认它,但 Gmail 会直接忽略整条声明 - 避免使用
inlineCssOnElement()单独处理节点,批量调用convert()更可靠
Node.js 场景下 juice 的三个翻车点
juice.inlineContent() 常被选作 Node.js 方案,但默认行为与邮件场景错配严重:
- 它保留
@media查询,而所有邮件客户端都不支持——必须提前用postcss-preset-env拆成桌面/移动端两套纯静态 CSS - 它不自动读取
<link href="email.css">,必须手动fs.readFileSync('email.css', 'utf8') - 它默认不加
!important,但 Outlook 2016 for Windows 要求关键样式(如color、font-size)带!important才生效
参数差异:传入的 options 里 preserveImportant: true 有用,但 applyWidthAttributes: true 反而可能破坏表格布局——邮件里 width="600" 属性比 style="width: 600px" 更可靠。
模板构建阶段就要锁定内联路径
自动化失败往往不在转换环节,而在模板源头。真正省事的做法是:从模板设计开始就拒绝依赖 CSS 类名或选择器。
可执行动作:
- 用
<table> 布局,不用 <code><div> —— 因为 <code>display: table-cell在 Outlook 里不可靠,但原生<td width="200"> 一定生效 <li>字体栈写成 <code>font-family: "Helvetica Neue", Helvetica, Arial, sans-serif,别用system-ui或变量字体 - 颜色统一用十六进制(如
#007bff),禁用rebeccapurple、hsl()等新语法 - 图片必须带
width、height、alt,且 URL 为绝对路径——相对路径在多数客户端里 404
最容易被忽略的点:所有样式最终要经真实客户端测试,不是看浏览器预览。Gmail 会剥离整个 <style></style> 块,Outlook Desktop 用 Word 渲染引擎,Apple Mail 对 line-height 解析异常——这些都得靠 Litmus 或 Email on Acid 实测,不能靠文档赌运气。











