写点什么

前端遗留技术与现代功能的对抗,邮件开发注定是件苦差事

作者 | s0.rumi

  • 2023-09-11
    北京
  • 本文字数:4529 字

    阅读完需:约 15 分钟

大小:2.30M时长:13:23
前端遗留技术与现代功能的对抗,邮件开发注定是件苦差事

首先,如果大家点进来的原因是厌烦了开发邮件系统,请允许我先对各位的悲惨遭遇表达最诚挚的慰问。

 

说说结论,我认为邮件系统的开发可以说是能在笔记本电脑上完成的、最恶心的工作,没有之一。我们做的一切似乎都没有意义,只能像疯子一样反复测试一切,那种感觉跟清理浴室地板上莫名其妙的顽固污渍倒有几分相似。

 

总之,希望文章接下来的内容能帮大家厘清整个混乱的局面,提供一点有用的建议,特别是让您在绝望中找到一丝活下去的勇气。

 

邮件开发是干啥的?

 

理论上讲,邮件系统的开发其实跟网站开发应该比较相似。电子邮件在本质上只是个 HTML 文档,跟网页一样,只不过是在邮件客户端、面非网络浏览器中呈现视觉效果。但除此之外,二者都能渲染,也就是把 HTML 代码转换成文本、图形和图像——即内容的可视化。

 

其实在 2005 年那会,网站和邮件系统的开发其实非常相似。浏览器和邮件客户端会以几乎相同的方式呈现 HTML,而且功能也相差不大。但是,尽管 Web 标准不断发展且持续入驻网络浏览器,但邮件客户端这头却似乎陷入了时停——至今无甚变化。

 

如今,我们在开发网站时可以支持各种酷炫且高效的功能,比如网格、Flexbox、夜晚模式、过渡,而且所有主要浏览器都能兼容。但另一方面,这些功能在邮件客户端中则分以下三种情况:

  1. 完全不受支持;

  2. 无法按预期工作;

  3. 在某些邮件客户端中无法兼容。

 

所以,如果大家希望一定比例的用户(至少得有 95%吧)能按预期查看邮件内容,那就只能坚持使用最基本的 HTML 和 CSS 功能。而且即使这样,成功率也不是 100%……

 

而且更离奇的是,如今 Web 开发中最糟糕的实践竟然仍是邮件开发中的最佳实践。下面,就让我们一探究竟。

 

首先,如果大家点进来的原因是厌烦了开发邮件系统,请允许我先对各位的悲惨遭遇表达最诚挚的慰问。

说说结论,我认为邮件系统的开发可以说是能在笔记本电脑上完成的、最恶心的工作,没有之一。我们做的一切似乎都没有意义,只能像疯子一样反复测试一切,那种感觉跟清理浴室地板上莫名其妙的顽固污渍倒有几分相似。

总之,希望文章接下来的内容能帮大家厘清整个混乱的局面,提供一点有用的建议,特别是让您在绝望中找到一丝活下去的勇气。

 

为什么要用<table> 元素?

 

邮件开发最让人头痛,当数其中大量使用到 table 元素,以及永无止境的<tr>和<td>字符串。但是,为什么会这样?

 

根据相关文献的解释,微软 Outlook 使用着与 Word 相同的渲染引擎。也就是说,在 Outlook 中打开电子邮件基本上相当于在 Word 中打开文档,所以我们得先摆正思路——手头开发的并不是电子邮件,而是 Word 文档。

 

有朋友可能会想,“不会吧,Word 里可没有多少布局和样式工具……”说得没错!但它有 table,而且只有 table。所以任何想要正确实现可视化的内容都必须是 table。没有其他办法了,请大家收下这份表格大礼。

 

为了证明这一点,以下是苹果发送的现代电子邮件被粘贴进微软 Word 2013 后的样子:

 


微软 Word 2013 中打开的苹果发票邮件

 

神奇吧,这格式多么规整。而之所以能这么规整,是因为邮件的 HTML 中包含 75 个<tr>和 122 个<td>。看看 HTML 格式,就知道内容有多乱了。

 

为什么要使用内联样式?


跟常规 HTML 文档一样,电子邮件也可以具有 CSS 样式。如果各位朋友足够理智,肯定会想到把它们放在文档的<head>标记当中。根据“如何开发邮件……”支持页面中的<link>和<style>部分的说明,这种处理方式能让样式得到良好渲染。

 

我们可以选择“正确的方式”,也就是发送邮件、打开邮件,然后发现它的呈现效果跟预期一致。但问题是用户不只会接收邮件,还会撰写自己的邮件,甚至进一步再做转发。

 

那在转发电子邮件时,具体会发生什么?根据 Stack Overflow 上的回答,简单来讲,<head>中的所有内容都会被删除。就是说我们向其中添加的任何新式,都会被 Gmail 无情抛弃。

 

唯一不会被删除的样式就只有内联样式。因此,如果希望电子邮件在转发之后仍然正常显示,那就只能使用内联样式。

 

以下是我转发的苹果通知邮件:



在 Gmail 中渲染得到的转发邮件

 

看着没什么毛病,对吧?那是因为其中用到了 40 个内联样式属性。不信?大家可以看看这封邮件的 HTML 代码证明我没说谎:

https://dodov.dev/blog/why-does-email-development-have-to-suck/email-inline-styles.html

 

下面我们删掉内联样式,看看更新之后的 HTML。在浏览器端,二者的显示效果几乎相同,因为内联样式所提供的样式会被复制到<head>当中作为后备。但因为转发邮件时这些样式会被删除,所以我们的样式就彻底消失了:



Gmail 中渲染的、不带内联样式的转发邮件

 

可以看到,标题、页脚、间距全都是一团糟……这显然不对劲,但至少还有个合乎逻辑的理由——保障安全。电子邮件客户端在渲染 HTML 之前,会对其进行预处理以保证安全,样式也是这样被丢掉的。

 

如果大家希望自己的邮件在转发时看着能有点章法,那就必须拿起内联样式的“颜料瓶”冲着 CSS 之墙拼命喷洒。

 

颜色反转

 

在开发网站的时候,我们会用 Prefers-Scheme 来检测用户是否在 DAMB 模式下查看,并相应更改当前页面的调色板。您猜怎么着?大多数电子邮件客户端还不支持这项功能。时间已经过去了 20 年,Apple Mail 等少数客户端倒是支持,但 Gmail 却采用了另一种不同的方法……

 

在谷歌看来,一切问题说到底都是概率论问题。只要在数学上具备可行性,那就可以完全不管少数情况下的怪异效果,这就免去了重新设计调色板和其他颜色的麻烦。

 

所以在夜晚模式下,Gmail 会简单将邮件中的所有颜色反转——包括背景、边框和文本颜色,如下图所示:



iOS 版本的 Gmail 客户端,会在夜晚模式时直接将颜色反转

 

可悲的是,这事我们防不胜防、几乎没办法做预先控制。唯一的办法就是尽量拣选那些在反转之后效果仍然不错的配色,保证图像在常规和反转配色时都有过得去的观感……这事不容易,大家多留点时间吧。

 

全宽内容

 

在移动设备上,我们可能需要让内容从一端显示到另一端,正常的网站也都是这么显示的。大多数移动邮件客户端也都支持这种方案,除了……Gmail。

 

Gmail 在每封邮件的侧面,都放置了一块莫名其妙的 16 像素空白。

 


Apple Mail 和 Gmail 的侧边留白比较

 

我们没法去掉这块留白。查看边距?已经是 0 了。填充?是 0。而且!important 已经全部应用过了。反正就是解决不了,你既检测不到它、也没法做进一步处理。忍着吧,强迫症们!


自定义字体

 

对组织来说,品牌中最重要的组成部分应该就是字体了吧,所以我们当然想在邮件中也继续使用自己的独特字体……可以吗?行啊,除了 Gmail。

 

大多数电子邮件客户端都不支持 font-face 字体,但这却是 Gmail 那边使用率最高的字体。

Stack Overflow 发帖有云,这时候只能使用设备操作系统提供的本地字体。总之,希望各位的品牌多跟 Arial 和 Times New Roman 合作!🤞

 

响应式图像

 

有时候,我们可能需要张台式机壁纸,又想把同样的画面也放到移动设备端。假设大家已经读过 MDN 的响应式图像指南,就会想到这时应该使用 srcset……没错,只是邮件客户端这边不支持。

 

为了解决这个问题,我们需要使用多个<img>元素,然后使用媒体查询把它们隐藏掉。但如果稍不注意,这里也有陷阱:

 

 

@media (max-width: 600px) and (prefers-color-scheme: dark) {/* only show on mobile in dark mode */.something { display: block }}
复制代码

 

这里我们只能倒转逻辑,使用两个单独的媒体查询,并依靠 CSS 级联来覆盖掉之前的样式:

/* always show… */.something { display: block }/* …but hide on desktop… */@media (min-width: 601px) {.something { display: none }}/* …and in light mode… */@media (prefers-color-scheme: light) {.something { display: none }}
复制代码

 

大家可能感受得到,这东西太容易出错了。

 

其他小问题


如果大家已经读过这篇文章,但仍不相信开发电子邮件有多么痛苦,那下面咱们再看点别的小例子:

  • Outlook 中没有 table 填充。所以当我们在<table>上设置 CSS 填充时,Outlook 只会对表内的所有<td>元素应用填充。但我们至少可以覆盖掉<td>元素本身的填充……

  • 大多数电子邮件客户端会扫描文本内容中的邮件地址和电话号码,然后把它们转换成看起来很丑的蓝色<a>链接形式。我们必须把它们打包进<a>标签,并提前标记再删除样式才能避免这个问题:

 

<a style="color: inherit; text-decoration: none;" href="">some@example.com</a>
复制代码

 

如果邮件地址是条指向空 href 的链接,那电子邮件客户端就不会这么处理。在 Outlook 中,列表项目还应该用边距分开,且列表本身需要缩进来保证保留边距:

 

<ul style="margin: 0 0 0 18px; padding: 0;"><li style="margin-bottom: 24px;">foo</li><li style="margin-bottom: 24px;">bar</li><li style="margin-bottom: 0;">baz</li></ul>


复制代码

 

最后一个条目须明确设置 0 边距,避免底部再留额外的空间。像这样的问题,还有很多……

 

有办法解决吗?

 

其实并没有太好的解决办法,大家别抱什么希望。所以在跟设计师合作时,一定要让他们知道邮件系统的开发有多么复杂。告诉他们关于上述问题的所有细节,提醒他们在设计时务必考虑到这些现实挑战。

 

而且即便通过协商得出了更简洁的设计,上述问题也只是得到了缓解,它们仍然存在。另外,永远别以为你可以编写“干净的代码”来让电子邮件系统始终保持整洁、正常工作。总会在一些地方,总会有一些东西就是不起作用。在邮件开发当中,我们唯一能够确定的就只有这点。

 

当然,MJML 和 React Email 等项目能帮上不少忙。它们会努力把电子邮件客户端里那些晦涩难懂的怪癖抽象出去。例如,使用 MJML,我们可以忘掉所有复杂性,让创建邮件真正变得简单:

 

<mj-column><mj-image width="64px" src="/assets/logo.png"></mj-image><mj-divider border-color="#88846f"></mj-divider><mj-text font-size="24px" color="#f8f8f2">Hello World</mj-text></mj-column>
复制代码

 

这样看着就好多了,对吧?用不着再处理一大堆<tr>和<td>,MJML 会在后台帮各位解决。总之,欢迎大家多体验体验 MJML,并参阅 Josh Comeau 的文章了解这款强大的 HTML 邮件开发工具:

https://www.joshwcomeau.com/react/wonderful-emails-with-mjml-and-mdx/

 

写在最后

 

与符合 Web 标准的网络浏览器不同,电子邮件客户端从不给任何人面子。电子邮件开发之所以很糟糕,就是因为我们在网站构建时所使用的很多现代功能在邮件这边根本不受支持。这就迫使我们只能使用遗留技术,同时需要考虑各种各样的极端情况。

 

电子邮件的构建方式跟网站不同,所以千万别像设计网站那样设计电子邮件。尽量用更简单的布局,同时配合 MJML 这类项目消除种种令人头痛的问题。各位,你们一定能挺过去!

 

最后,别觉得丢脸,没人能搞定邮件客户端……没人可以。

 

原文链接:

https://dodov.dev/blog/why-does-email-development-have-to-suck


相关阅读:

前端精准测试实践

大前端测试的思考和在语雀的实践分享

Java 后端有哪些不用学的技术?劝退。

前后端分离技术体系

2023-09-11 10:342377

评论

发布
暂无评论
发现更多内容

通义灵码上下文能力解析:自由组合需求描述,生成结果更高效

阿里云云效

阿里云 云原生 通义灵码

AI 技术在英语学习中的应用

北京木奇移动技术有限公司

软件外包公司 AI英语学习 AI技术应用

「金融证券行业」 如何搭建自己的研发智能管理体系?

禅道项目管理

项目 金融 银行 项目管理软件 软件项目管理

微信小游戏的上线流程

北京木奇移动技术有限公司

游戏开发 微信小游戏 软件外包公司

“深时数字地球”国际大科学计划系列工作坊持续开放!专业友好可复现,赋能科学智能生态合作(1)

ModelWhale

科学智能 AI4S DDE 深时数字地球

极兔快递Java岗,薪资18-35K,看看难度

王中阳Go

Java

从三流作者到虎嗅公众号头条——我的AI写作方法论

田威AI

AI

WebGL与APP之间的通讯方式

北京木奇移动技术有限公司

软件外包公司 webgl开发 webgl外包公司

CST软件TDR时域仿真实例

思茂信息

cst CST软件 CST Studio Suite

TiDB 全文搜索功能公开测试中

TiDB 社区干货传送门

新版本/特性解读

浅聊一下搭建企业私有知识库的可行方案

为自己带盐

人工智能 RAG应用

WebGL与App的集成开发

北京木奇移动技术有限公司

软件外包公司 webgl开发 webgl外包开发

从炫技到实用,天工超级智能体(Skywork Super Agents)的破冰之旅

脑极体

AI

#放码来战.端云一体化开发#HarmonyOS 5 【农民叔叔】04.创建端云一体化工程项目

与辉鸿蒙

HarmonyOS HarmonyOS NEXT 端云一体化

从40秒到11毫秒:TiDB环境下一次SQL深潜优化实战

TiDB 社区干货传送门

性能调优 7.x 实践 TiDB Cloud TiDB第四届征文-运维开发之旅

鸿蒙仓颉开发语言实战教程:实现商城应用详情页

幽蓝计划

四位图灵奖掌舵 2025智源大会揭示AI进化新路径

智源研究院

英特尔至强6家族又添新成员:释放GPU潜能,AI性能更出色

E科讯

微信小游戏外包开发流程

北京木奇移动技术有限公司

小游戏开发 软件外包公司 游戏开发公司

混合应用开发新范式:2025年企业级移动生态降本增效破局点

xuyinyin

通义灵码上下文能力解析:自由组合需求描述,生成结果更高效

阿里巴巴云原生

阿里云 云原生 通义灵码

蚂蚁集团数字蚂力与珀莱雅战略合作:打造AI智能化应用矩阵 提升消费者体验和企业竞争力

Lily

全国独家线下面授 | 大规模敏捷LeSS认证上海6月19-21日【报名享多重福利优惠】

ShineScrum

MySQL 派生表查询导致 Crash 的根源分析与解决方案

GreatSQL

低成本也能实现大模型应用开发,英特尔与火山引擎是怎么做到的?

E科讯

【CodeBuddy】三分钟开发一个实用小功能之:3D旋转相册

jimaks

CSS

"催化型领导力(Catalyst Leadership)" 敏捷领导者CAL 1认证 · 8月9-10日(周末班)

ShineScrum

#放码来战.端云一体化开发#HarmonyOS 5 【农民叔叔】06.部署模板示例的云测工程到AGC云端

与辉鸿蒙

HarmonyOS HarmonyOS NEXT 端云一体化

“从PMO到VMO价值交付管理” — Agile VMO业务敏捷CVP认证 | 7月26-27日 · 上海线下

ShineScrum

2025上海国际人形机器人展览会

AIOTE智博会

机器人展 智能机器人展 人形机器人展

YashanDB:助力企业攻克AI时代数据管理难题,拥抱智能转型

极客天地

前端遗留技术与现代功能的对抗,邮件开发注定是件苦差事_架构/框架_InfoQ精选文章