今早有用户反馈一个问题:系统发送的公告邮件,在企微客户端打开标题有乱码。我们查了一下各个客户端,邮件系统 Web 端打开是正常的,PC 客户端也是正常的,企微的 PC 客户端也是正常的。因此,问题被归结为客户端兼容性问题,按惯例大概是不了了之。
虽然企微平时问题不少,但作为工作IM,重度使用。按照企微以前的尿性,问题修复很慢很慢的。因此,就算问题不是出在自己系统上,还是想看看到底为什么,能否绕过去。
想知道企微为什么不兼容,就得从网络协议层面出发,看看这份邮件报文长什么样,是否有什么特殊之处。本来以为必须通过 POP 协议请求邮件原文,差点想放弃。好在,邮件系统 Web 端上可以查看原文。
查看原文发现,原来是邮件标题头 Subject 被企微截短了:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
Received: ****
Mime-Version: 1.0
Date: Fri, 20 Dec 2024 10:55:07 +0800
From: ****
To: ***
Subject: =?UTF-8?q?=E4=B8=80=E4=BA=8C=E4=B8=89=E5=9B=9B=E4=BA=94=E5=85=AD=E4=B8=83?=
=?UTF-8?q?=E5=85=AB=E4=B9=9D=E5=8D=81=E4=B8=80=E4=BA=8C=E4=B8=89=E5=9B=9B?=
=?UTF-8?q?=E4=BA=94=E5=85=AD=E4=B8=83=E5=85=AB=E4=B9=9D=E5=BB=BF=E4=B8=80?=
=?UTF-8?q?=E4=BA=8C=E4=B8=89=E5=9B=9B=E4=BA=94=E5=85=AD=E4=B8=83=E5=85=AB?=
=?UTF-8?q?=E4=B9=9D=E4=B8=89=E4=B8=80=E4=BA=8C=E4=B8=89=E5=9B=9B=E4=BA=94?=
=?UTF-8?q?=E5=85=AD=E4=B8=83=E5=85=AB=E4=B9=9D=E5=9B=9B=E4=B8=80=E4=BA=8C?=
=?UTF-8?q?=E4=B8=89=E5=9B=9B=E4=BA=94=E5=85=AD=E4=B8=83=E5=85=AB=E4=B9=9D?=
=?UTF-8?q?=E4=BA=94=E4=B8=80=E4=BA=8C=E4=B8=89=E5=9B=9B=E4=BA=94=E5=85=AD?=
=?UTF-8?q?=E4=B8=83=E5=85=AB=E4=B9=9D=E5=85=AD=E4=B8=80=E4=BA=8C=E4=B8=89?=
=?UTF-8?q?=E5=9B=9B=E4=BA=94=E5=85=AD=E4=B8=83=E5=85=AB=E4=B9=9D=E4=B8=83?=
=?UTF-8?q?=E4=B8=80=E4=BA=8C=E4=B8=89=E5=9B=9B=E4=BA=94=E5=85=AD=E4=B8=83?=
=?UTF-8?q?=E5=85=AB=E4=B9=9D=E5=85=AB=E4=B8=80=E4=BA=8C=E4=B8=89=E5=9B=9B?=
=?UTF-8?q?=E4=BA=94=E5=85=AD=E4=B8=83=E5=85=AB=E4=B9=9D=E4=B9=9D=E4=B8=80?=
=?UTF-8?q?=E4=BA=8C=E4=B8=89=E5=9B=9B=E4=BA=94=E5=85=AD=E4=B8=83=E5=85=AB?=
=?UTF-8?q?=E4=B9=9D=E7=99=BE?=
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
X-CM-TRANSID:DFgsCgDxTz6K3GRnfAt2AA--.486S3
|
企微客户端解析邮件时,是先对 Subject 头进行截短,截到 =83=E5=85
这个位置,然后再解码。由于这一行的结尾标识 ?=
丢掉了,所以就解码不出来,造成乱码。
问了一下 AI ,发现这样一行是一种编码方式:
1
|
=?UTF-8?q?=E4=B8=80=E4=BA=8C=E4=B8=89=E5=9B=9B=E4=BA=94=E5=85=AD=E4=B8=83?=
|
=?
表示编码的开头;
UTF-8
表示字符集( chatset );
q
表示 Quoted-Printable 编码,在 RFC2045 中有定义;
?=
之后是编码后的内容;
- 最后的
?=
表示编码结束;
不得不说,目前的 AI 小助理还是很好用的,换以前要去看黑压压一大片的 RFC 文档。猜猜我是用了哪个厂的 AI 产品?哈哈哈😄
为了对比测试,我用邮件系统的 Web 客户端发了一封一模一样的邮件,发现企微客户端上也不会乱码。对比邮件原文后发现,Subject 邮件头的写法是不一样的:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
Subject: =?UTF-8?b?5LiA5LqM5LiJ5Zub5LqU5YWt5LiD5YWr5Lmd5Y2B5LiA5LqM5LiJ5Zub5LqU?=
=?UTF-8?b?5YWt5LiD5YWr5Lmd5bu/5LiA5LqM5LiJ5Zub5LqU5YWt5LiD5YWr5Lmd5LiJ?=
=?UTF-8?b?5LiA5LqM5LiJ5Zub5LqU5YWt5LiD5YWr5Lmd5Zub5LiA5LqM5LiJ5Zub5LqU?=
=?UTF-8?b?5YWt5LiD5YWr5Lmd5LqU5LiA5LqM5LiJ5Zub5LqU5YWt5LiD5YWr5Lmd5YWt?=
=?UTF-8?b?5LiA5LqM5LiJ5Zub5LqU5YWt5LiD5YWr5Lmd5LiD5LiA5LqM5LiJ5Zub5LqU?=
=?UTF-8?b?5YWt5LiD5YWr5Lmd5YWr5LiA5LqM5LiJ5Zub5LqU5YWt5LiD5YWr5Lmd5Lmd?=
=?UTF-8?b?5LiA5LqM5LiJ5Zub5LqU5YWt5LiD5YWr5Lmd55m+5LiA5LqM5LiJ5Zub5LqU?=
=?UTF-8?b?5YWt5LiD5YWr5Lmd5Y2B5LiA5LqM5LiJ5Zub5LqU5YWt5LiD5YWr5Lmd5bu/?=
=?UTF-8?b?5LiA5LqM5LiJ5Zub5LqU5YWt5LiD5YWr5Lmd5LiJ5LiA5LqM5LiJ5Zub5LqU?=
=?UTF-8?b?5YWt5LiD5YWr5Lmd5Zub5LiA5LqM5LiJ5Zub5LqU5YWt5LiD5YWr5Lmd5LqU?=
=?UTF-8?b?5LiA5LqM5LiJ5Zub5LqU5YWt5LiD5YWr5Lmd5YWt5LiA5LqM5LiJ5Zub5LqU?=
=?UTF-8?b?5YWt5LiD5YWr5Lmd5LiD5LiA5LqM5LiJ5Zub5LqU5YWt5LiD5YWr5Lmd5YWr?=
=?UTF-8?b?5LiA5LqM5LiJ5Zub5LqU5YWt5LiD5YWr5Lmd5Lmd5LiA5LqM5LiJ5Zub5LqU?=
=?UTF-8?b?5YWt5LiD5YWr5Lmd55m+?=
|
每一行的结构还是一样的,只不过编码部分变成了:
由此定位到问题是编码方式不同导致的,但为什么 Quoted-Printable 会乱码呢?是不是换成 base64 就不会呢?想回答这两个问题,那得进一步看看这两种编码方式的区别。同样先问问 AI 🤔
Quoted-Printable
Quoted-Printable 是一种内容传输编码,它把一个字节中的非 ASCII 部分变成成 =xx
的形式。其中,xx
是该字节的十六进制形式。 ASCII 部分则原封不变,因此完全兼容 ASCII 。
例子 |
UTF-8字节 |
编码结果 |
小菜 |
0xb0 0xe5 0xe8 0x8f 0x9c 0x8f (共6字节) |
=B0=E5=E8=8f=9C=8F (共18字节) |
fasion |
0x61 0x66 0x69 0x73 0x6e 0x6f (共6字节) |
fasion (共6字节) |
由此可见,对于非 ASCII 字节,编码后所需的字节数放大了 3 倍。因此,Quoted-Printable 更适用于 ASCII 文本,或者只有极少量非 ASCII 的场景。
base64
base64 是另一种内容传输编码,它对所有输入的字节都一视同仁,统一编码成 64 进制可打印字符。同样,base64 编码结果所需的字节数也会放大,大概是 1.5 倍左右。
编码方式 |
优点 |
缺点 |
适用场景 |
Quoted-Printable |
ASCII不会放大 |
非ASCII放大3倍 |
大部分为ASCII的场景 |
base64 |
ASCII放大1.5倍 |
非ASCII只放大1.5倍 |
大部分为非ASCII的场景 |
至此,案件水落石出:Quoted-Printable 编码方式内容放大倍数很大,更容易达到企微手机端的限制,导致内容被截短而出现乱码现象。因此,我们调整了发件组件的默认编码设置。
但问题并未彻底解决,如果标题很大,理论上还是会触发长度限制。为此,我们测了一下,发现:
- Quoted-Printable 编码方式,标题达到大约40+汉字,就会触发企微截短 BUG;
- base64 编码方式,标题达到大约100+汉字,也会触发企微截短 BUG;
40 比 100 ,跟放大倍数 3 比 1.5 ,大致是吻合的。
问题来了:请问企微,这些问题你们想修一修吗?🐶
- 标题能不能不要截短?
- 标题就算真的必须截短,能不能解码后再截短?并且在客户端上有相关提示?
- 还有不少小问题,比如推送企微协作群( AppChat )消息不能 at 人,而群机器却可以?
- etc
订阅更新,获取更多学习资料,请关注我们的公众号: