写点什么

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

作者 | 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:342566

评论

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

华为云:一切皆服务,共建全场景智慧金融

极客天地

尚硅谷SSM新版视频教程发布

小谷哥

洞见科技纪凯:隐私计算助力「全链路」金融客户经营

洞见科技

隐私计算

NFT链游戏系统开发元宇宙GameFi搭建

薇電13242772558

dapp NFT 元宇宙

ModuleNotFoundError_No_module_named通俗的解释和方法

和牛

测试

李宏毅《机器学习》丨4. Deep Learning(深度学习)

AXYZdong

机器学习 7月月更

纯css实现:如何做个完美的平行四边形

南极一块修炼千年的大冰块

7月月更

可观测性提升软件工程质量,观测云出席2022 QECon全球软件质量&效能大会

观测云

大咖说·图书分享 | HaaS 物联网设备云端一体开发框架

大咖说

阿里巴巴 物联网 大咖 HaaS

直播预告 | 7月22日《开源安全治理模型和工具》线上研讨会

安势信息

开源安全 SCA工具 开源软件供应链 SBOM SLSA

智慧灯杆展会|2022南京国际智慧灯杆及智慧路灯展览会

AIOTE智博会

2022第十四届南京国际智慧工地展览会|智慧工地展

AIOTE智博会

智慧工地展览会

国产操作系统生态建设,小程序技术来帮忙

Speedoooo

小程序 国产操作系统 小程序容器 桌面应用

百度工程师眼中的云原生可观测性追踪技术

百度Geek说

Java 云原生

重磅预告!易观分析联合微软、中央财经大学,共话数字经济

易观分析

数据驱动

大数据开发技术入门学习方法有哪些

小谷哥

零基础如何学习大数据开发知识

小谷哥

CSDN Meetup 回顾 丨从数据湖到指标中台,提升数据分析 ROI

Kyligence

数据分析 指标中台

LP流动性质押挖矿系统开发详细程序

开发微hkkf5566

openGauss内核分析:查询重写

华为云开发者联盟

数据库 后端 查询 SQL语言 openGauss内核

瓜分30万奖金!DeepRec CTR模型性能优化天池挑战赛来啦

阿里云大数据AI技术

深度学习

6W+字记录实验全过程 | 探索Alluxio经济化数据存储策略

Alluxio

数据湖 数据膨胀 降本增效 Alluxio 大数据 开源

7月《中国数据库行业分析报告》发布!居安思危,安全先行

墨天轮

数据库 腾讯云 阿里云 国产数据库 数据库安全

不懂点儿统计学,《星球大战》白看了

图灵教育

统计学 贝叶斯定理

业务出海,灵感乍现前要先「把手弄脏」

融云 RongCloud

深圳web前端技术学习费用是多少?尚硅谷前端培训

小谷哥

如何学习好web前端开发技术知识

小谷哥

如何用度量数据驱动代码评审的改善

思码逸研发效能

数据分析 研发效能 科技 效能度量

21条最佳实践,全面保障 GitHub 使用安全

SEAL安全

GitHub 安全

【字体反爬】猫X眼YingShi,我们又来欺负你了,用到了 OCR 识别技术

梦想橡皮擦

Python 爬虫 7月月更

架构实战营模块七作业

Geek_Q

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