【AICon】AI 基础设施、LLM运维、大模型训练与推理,一场会议,全方位涵盖! >>> 了解详情
写点什么

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

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

评论

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

AIGC的隐私安全问题及隐私保护技术 | 社区征文

京东科技开发者

隐私计算 语言模型 ChatGPT 企业号 2 月 PK 榜 LLM

腾讯前端必会react面试题合集

xiaofeng

前端 React

2022年最新数据库调查报告:中国使用率最高的数据库云厂商是谁?

墨天轮

数据库 腾讯云 阿里云 华为云 上云

谈JVM xmx, xms等内存相关参数合理性设置

京东科技开发者

JVM 内存 垃圾回收 吞吐量 企业号 2 月 PK 榜

2022年中国小微企业云财税服务市场专题分析

易观分析

数字化 财政 财税

校招前端高频react面试题合集

夏天的味道123

前端 React

几个你必须知道的React错误实践

xiaofeng

前端 React

瓴羊Quick BI拥有可视化大屏功能,精准掌握所有数据内容!

小偏执o

Vue虚拟dom是如何被创建的

yyds2026

Vue 前端

【华秋电子】晶体的选择有哪些参数?

华秋电子

2023前端一面vue面试题合集

yyds2026

Vue 前端

阿里云IoT企业物联网平台 可用地域区 和 接入点信息速查——实践类

阿里云AIoT

阿里云 物联网 IoT

用javascript分类刷leetcode9.位运算(图文视频讲解)

js2030code

JavaScript LeetCode

文章转载 | 紫龙上海CTO王琦:我们对游戏工业化的探索

龙智—DevSecOps解决方案

游戏开发 游戏引擎 紫龙游戏

从实现一个React到深度理解React框架核心原理

夏天的味道123

前端 React

前端一面常见react面试题(持续更新中)

夏天的味道123

前端 React

前京东高级副总裁周伯文提前1年布局ChatGPT,现招募多名合伙人

B Impact

cmp云管平台专业厂商选择技巧看这里!

行云管家

云计算 云服务 云管平台 云计算管理工具

华为云携手金蝶,探索高成长型企业“数字化创新管理”之路

华为云开发者联盟

云计算 后端 华为云 企业号 2 月 PK 榜 华为云开发者联盟

彻底搞懂React-hook链表构建原理

夏天的味道123

前端 React

滴滴前端高频react面试题汇总

xiaofeng

前端 React

2023年优质的数据库审计厂商当属行云管家!

行云管家

等保 等级保护 数据库审计

前端leetcde算法面试套路之堆

js2030code

JavaScript LeetCode

代码质量与安全 | ChatGPT能帮到你什么还有待探索,但人工智能真的可以帮你做自动化测试

龙智—DevSecOps解决方案

人工智能 AI 软件测试 测试 自动化测试

线上研讨会报名 | Perforce、中手游、星思半导体专家邀您一起畅聊如何通过数字资产管理与版本控制赋能大规模研发

龙智—DevSecOps解决方案

版本控制 数字资产 游戏开发 数字资产管理 芯片研发

你要的react+ts最佳实践指南

xiaofeng

前端 React

基于 IoT+TSDB+Quick BI 云产品架构的楼宇环境监控实战——实践类

阿里云AIoT

数据库 监控 物联网 传感器 测试技术

前端leetcde算法面试套路之回溯

js2030code

JavaScript LeetCode

CI/CD | 深入研究Jenkins后,我挖掘出了找到了摆脱低效率低下的方法

龙智—DevSecOps解决方案

ci 持续集成 jenkins

Atlassian Server用户新选择 | 数据中心产品是否适合您的企业(2)?

龙智—DevSecOps解决方案

Atlassian 数据中心版 server版

还在苦于提升代码质量?快来试试这个方法

博文视点Broadview

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