开发插件解决 Claws Mail 看不到 Extmail 发来邮件内容的问题

2012-04-25

实验室的邮件系统最近改用了国产开源邮件服务器——Extmail。我在使用过程中发现一个问题:Claws Mail 客户端收到来自 Extmail web 界面发来的带有附件的邮件,内容均为空白,既无正文也无附件。而使用 Foxmail 等其他客户端接收邮件,则正常。经测试,发现问题出在 Extmail web 界面生成的邮件头中的这一行: Content-Transfer-Encoding: base64。

如果将这一行删除,则 Claws Mail 可以正确显示邮件正文与附件。那么,这是 Extmail 的问题还是 Claws Mail 的问题呢?既然这一问题只出现含有附件的邮件中,就从实现邮件附件的规范——MIME 的 Multipart Content-Type 入手分析。查阅 RFC 1341RFC 2046 相关章节,其中明确说明了 multipart 类型的 Content-Transfer-Encoding 只允许是 7bit、8bit 或 binary,而具体内容(正文和附件)的 Content-Transfer-Encoding 应在各个 part 的头部声明。因此,Extmail 在邮件头部指定“Content-Transfer-Encoding: base64”是不符合 RFC 的。而 Claws Mail 可能对标准的执行过于严格,容错能力不足,因此不能显示不符合规范的 multipart 邮件的正文和附件。

我又查看了 Foxmail、Coremail 等 X-Mailer 发来的 multipart 邮件,发现多数 X-Mailer 构造的 multipart 邮件在头部都不指定 Content-Transfer-Encoding,只在下面的各个 part 中分别指定 Content-Transfer-Encoding。作为具有缺省值、可以省略的字段,multipart 邮件头部不指定 Content-Transfer-Encoding 应该是符合 RFC 的,这些邮件在 Claws Mail 中解析正确。

因此,这个问题的根源在于 Extmail 未严格遵守 RFC。简单查了一下,构造 multipart 邮件的相关代码位于 libs/Ext/App/Compose.pm 文件。委托 Jeoygin 同学修改代码,却得知 Extmail 在这块的设计逻辑有些混乱,并不是改一两行代码就能搞掂的,有一些纠结的逻辑必须重构。考虑到这是实验室的生产环境,加之受影响的只有我等另类用户,就不在服务器上折腾了。

退而求其次,在客户端解决吧。要么让 Claws Mail 在解析邮件时忽略非标准的头部,要么在收到邮件之后将其修改正确再解析。Claws Mail 的功能丰富,但遍历各个功能,没有发现能够直接解决这类问题的选项。虽然可以通过 Action 或 Run command 机制调用外部脚本修改邮件文件,但实验发现总有一些小问题:或是需要额外的鼠标操作,或是不能及时刷新。于是决定发挥主观能动性,自己写个 Claws Mail 插件。我仿照官方提供的插件示例,实现了一个 ExtMailHeaderFixer。思路很简单,添加一个处理接收到的邮件的钩子函数,当收到 Extmail 发来的带有 multipart 和 base64 头的邮件时,将 Content-Transfer-Encoding: base64 修改为 X-ExtMail-Header-Encoding: base64 即可。之所以不在解析时处理,而要修改邮件,是因为实验发现 Claws Mail 确实可以解析符合 Content-Transfer-Encoding: base64 语义的 multipart 邮件(即将 multipart 整体进行 base64 编码),不仅如此,Claws Mail 还能解析不同格式多级内联的邮件,我不想失去这个挺酷的特性。之所以不删除 Content-Transfer-Encoding: base64 这一行,或者把 base64 修改成合法的 8bit,而把这一行修改成对客户端无影响的 MIME 扩展字段,是便于必要时快速恢复邮件原样。这个方案也有缺点,即相关的钩子函数只对 POP3 邮件有效,对 IMAP 邮件无效,Claws Mail 这样设计可能与两个协议的语义差别(接收或同步)有关。在我目前的使用场景中,这个问题不大。

在 32 位 Ubuntu 12.04+Claws Mail 3.8.0 和 64 位 Debian wheezy+Claws Mail 3.8.0 下测试通过。把代码释放出来,放在 sf.net,按传染性要求以 GPLv3 授权,方便遇到相同问题的朋友使用:http://sourceforge.net/projects/extmailhf/