写点什么

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

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

评论

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

ISC网络安全大会关于“新型网络犯罪打击与治理”的分析

郑州埃文科技

网络安全 isc

绿森林回收系统小程序开发

ALVIS

完备的娱乐行业知识图谱库如何建成?爱奇艺知识图谱落地实践

爱奇艺技术产品团队

nlp 搜索 知识图谱

万能小哥系统开发是什么?

ALVIS

正式发布!中国信通院联合腾讯安全等起草单位,共同发布研发运营安全工具系列标准

腾讯安全云鼎实验室

云计算 中国信通院 安全工具系列标准

新工具上线!sdkmgr命令行助力流水线构建

科技汇

微服务架构设计模式-进程间通信

以吻封笺

微服务 设计模式

ONES 当选深圳信创联盟副理事长单位,助力国产软件工业发展

万事ONES

信创 ONES

LeetCode题解:61. 旋转链表,双指针,JavaScript,详细注释

Lee Chen

算法 大前端 LeetCode

家政公司管理系统开发介绍

ALVIS

绿色篮子系统开发是什么模式?

ALVIS

RocketMQ事物消息调研

crazylle

RocketMQ 事物消息

智慧农业陷转型困局,区块链如何“对症下药”?

CECBC

互联网大厂一手资料,25大专题,500多页,背废你就能吊打面试官

Java架构师迁哥

跑跑回收系统小程序开发

ALVIS

医院预约管理系统开发

ALVIS

主流分布式文件系统选型,写得太好了!

编程菌

Java 编程 程序员 计算机 技术宅

解读区块链技术对量子攻击的脆弱性以及量子安全区块链的解决方案

CECBC

这次不编故事了,阿里Spring Cloud Alibabab笔记,自己领吧

Java架构师迁哥

企业管云就用行云管家!省时省力省心!

行云管家

云计算 企业上云 行云管家 企业管云

行云管家荣获CFS第十届财经峰会2021科技创新引领奖!

行云管家

行云管家 财经峰会

爱奇艺搜索排序算法实践(内附福利)

爱奇艺技术产品团队

排序算法 nlp 搜索

希望体验更好的开发流程

escray

学习 极客时间 朱赟的技术管理课 7月日更

咔嗒回收系统小程序开发

ALVIS

好慷在家系统开发前景

ALVIS

ElasticJob 3.0.0:打造面向互联网生态和海量任务的分布式调度解决方案

SphereEx

数据库 开源

绿地回收系统开发|现成小程序

ALVIS

下一个颠覆的领域:区块链如何影响审计行业?(中)

CECBC

手撕环形队列系列二:无锁实现高并发

实力程序员

程序员 数据结构 并发 无锁 环形队列

本夕生活小程序定制开发

ALVIS

阿里云视频云发布实时高清VVC编码器Ali266,真正开启VVC商用之路

阿里云CloudImagine

阿里云 视频编码 视频处理 编码器 视频云

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