必须用内联CSS,因Gmail、Outlook(Windows桌面版)、Apple Mail会剥离<style>和<link>标签及class/id属性;juice.inlineContent()需手动加载CSS、处理!important、拆分响应式规则;CssToInlineStyles需预合并CSS、校验font-family引号;Premailer和Mailwind等CLI工具不自动处理base URL、Tailwind扫描及Outlook条件注释,最终须用Litmus实测。

必须用内联 CSS,没有例外。Gmail、Outlook(Windows 桌面版)、Apple Mail 会直接剥离 <style> 和 <link>,class/id 属性也可能被过滤掉——只认 。
juice.inlineContent() 在 Node.js 里怎么不出错
它不是“拿来即用”,默认配置在邮件场景下大概率翻车:
-
juice.inlineContent()不处理@media查询,响应式规则得提前拆成两套 CSS(桌面/移动端),再分别传入 - 它保留
!important,但 Outlook 2016 for Windows 只认带!important的样式,关键规则如color: #333 !important得手动加 - 它不自动读取
<link href="email.css">,必须自己用fs.readFileSync('email.css', 'utf8')加载内容再传进去 - 推荐调用写法:
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 });
CssToInlineStyles 在 PHP 项目里避坑要点
它比 juice 更贴近 PHP 工作流,但也有硬约束:
- 能自动提取 HTML 中的
<style>块,但对<link>仍无感,CSS 内容得先合并好再传入$cssToInlineStyles->convert($html, $css) - 默认不处理
!important优先级冲突:若多个选择器命中同一元素且含!important,结果可能和预期不一致——建议预处理时统一清理或加固关键规则 -
font-family这类复合值容易漏引号,比如把"Helvetica Neue", Arial变成Helvetica Neue, Arial,Outlook 会解析失败,需后置正则校验(/font-family:\s*([^;]+);/g+ 引号包裹逻辑)
Premailer 和 Mailwind 这类 CLI 工具的真实限制
它们省去代码集成,但掩盖了底层问题:
立即学习“前端免费学习笔记(深入)”;
- Premailer 默认把相对路径图片转成绝对 URL,但如果原始 HTML 里用了
../images/logo.png,它不会自动补 base URL,得配--base-url https://cdn.example.com参数,否则发出去就是 404 - Mailwind 依赖 Tailwind 编译产物,但它不校验你是否在
tailwind.config.js中启用了content路径扫描——如果没扫到邮件模板里的 class,那些样式根本不会进最终 CSS,内联也就无从谈起 - 所有 CLI 工具都不处理 Outlook 特有的
mso-xxx条件注释,需要你手动在 HTML 里写<!--[if mso]>...<![endif]-->,工具不会帮你插
真正难的不是选哪个工具,而是理解每一步输出是否经得起 Gmail 的 DOM 清洗、Outlook 的 Word 渲染引擎、iOS Mail 的媒体查询裁剪——内联只是起点,真实客户端还会二次魔改,必须拿 Litmus 或 Email on Acid 实测,不能只看本地浏览器渲染。



















