3 个版本
0.1.2 | 2024年1月25日 |
---|---|
0.1.1 | 2023年7月25日 |
0.1.0 | 2023年7月24日 |
#638 在 解析实现
170KB
4K SLoC
eml-codec
⚠️ 目前这只是一个解码器(即解析器),编码尚未实现。
eml-codec
是 Aerogramme 的子项目,Aerogramme 是由非营利组织 Deuxfleurs 开发的分布式加密 IMAP 服务器。它的目的是成为一个瑞士军刀,用于处理电子邮件,无论是构建 IMAP/JMAP 服务器、邮件过滤器(如反垃圾邮件)还是邮件客户端。
示例
let input = br#"Date: 7 Mar 2023 08:00:00 +0200
From: [email protected]
To: [email protected]
Subject: An RFC 822 formatted message
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
This is the plain text body of the message. Note the blank line
between the header information and the body of the message."#;
let (_, email) = eml_codec::parse_message(input).unwrap();
println!(
"{} just sent you an email with subject \"{}\"",
email.imf.from[0].to_string(),
email.imf.subject.unwrap().to_string(),
);
关于名称
这个库的目标不是实现特定的 RFC,而是一个瑞士军刀,用于解码和编码通常被认为是电子邮件的内容(通常简称为“eml”),因此得名:eml-codec。
目标
- 可维护性 - 修改代码不会产生回归,并且可以由项目外部的人进行。
- 兼容性 - 总是尝试解析,不要恐慌或返回错误。
- 全面性 - 作为编码电子邮件知识(现有 MIME 类型、现有头信息等)的通用项目。
- 类型安全 - 不要仅操作字符串/字节,而是利用 Rust 类型系统,以便在编译时受益于其安全检查。
缺失/已知错误
当前已知限制/错误
- 部分传输解码尚未实现
- 尚未实现国际化头信息(UTF-8)
- 尚未实现 Resent 头字段
- Return-Path/Received 头信息可能难以使用,因为它们的顺序很重要,而目前它们在最终数据结构中已丢失。
- 无效日期的日期时间解析可能返回
None
而不是回退到bad_body
字段 - 电子邮件头信息中的注释在解析过程中被删除
- 不提供对 message/external-body(从本地计算机读取数据)和 message/partial(聚合多个分段的电子邮件)的支持,因为它们似乎已经过时且具有风险。
设计
数据结构的概述(受 UML 类图约定启发)
测试策略
目前这个crate对其大多数解析函数进行了单元测试。它还被作为Aerogramme项目的一部分进行测试,Aerogramme是它的父项目,在那里它负责解析电子邮件。在这个项目中,eml-codec
的解析能力与Dovecot、Cyrus、Maddy和其他IMAP服务器进行了比较。
计划在大型电子邮件数据集(如Enron、jpbush、邮件列表等)上进行测试,但尚未完成。对该库进行模糊测试也很有趣,可能用于检测由于MIME的无穷递归导致的堆栈溢出等崩溃。
RFC和IANA参考文献
RFC
🚩 | # | 名称 |
---|---|---|
🟩 | 822 | ARPA互联网文本消息 |
🟩 | 2822 | 互联网消息格式(2001年) |
🟩 | 5322 | 互联网消息格式(2008年) |
🟩 | 2045 | ↳ 多用途互联网邮件扩展(MIME)第一部分:互联网消息体格式 |
🟩 | 2046 | ↳ 多用途互联网邮件扩展(MIME)第二部分:媒体类型 |
🟩 | 2047 | ↳ MIME(多用途互联网邮件扩展)第三部分:非ASCII文本消息头扩展 |
🟩 | 2048 | ↳ 多用途互联网邮件扩展(MIME)第四部分:注册过程 |
🟩 | 2049 | ↳ 多用途互联网邮件扩展(MIME)第五部分:一致性标准与示例 |
头部扩展 | ||
🔴 | 2183 | ↳ 在互联网消息中通信呈现信息:内容处置头字段 |
🔴 | 6532 | ↳ 国际化电子邮件头部 |
🔴 | 9228 | ↳ 送达至电子邮件头部字段 |
MIME扩展 | ||
🔴 | 1847 | ↳ MIME的安全多部分:Multipart/Signed和Multipart/Encrypted |
🔴 | 2387 | ↳ MIME Multipart/Related内容类型 |
🔴 | 3462 | ↳ 报告邮件系统管理消息的Multipart/Report内容类型 |
🔴 | 3798 | ↳ 消息处置通知 |
🔴 | 6838 | ↳ 媒体类型规范和注册过程 |
IANA
名称 | 描述 | 注意 |
---|---|---|
媒体类型 | 注册的媒体类型用于内容类型字段 | 目前只有MIME RFC中的媒体类型在eml-codec 中有专用支持。 |
字符集 | 支持用于charset 参数的字符集 |
它们都应该通过encoding_rs crate进行支持 |
技术前沿/替代方案
以下评估不是客观、中立、无偏见的评估。相反,它试图解释我为什么要编写这个库。如果您发现某些内容过时或客观错误,请随时提交PR或问题进行修复。在任何情况下,我认为eml-codec
都不是最好的,它只是解决问题的一种方法,我将其视为建筑中的一块石头。
mail_parser、mailparse 和 rust-email 是三个手动编写的解析器。这种手动编写的解析器不利于关注点的分离:mail_parser
和 mailparse
包含了数百行代码的庞大函数,其圈复杂度很高。由于这种复杂的逻辑,我过去在调试/修复此类代码时失败了。《code>rust-email 代码更易于阅读,但它的 MIME 部分实现被标记为不稳定。《code>mail_parser 被用于 stalwartlabs/mail-server 的 IMAP/JMAP/SMTP 服务器项目,而 rust-email
被用于基于电子邮件的聊天应用 Deltachat(然而 rust-email
的 MIME 解析未使用,Delta Chat 中重新实现了自定义的 MIME 解析器)。必须注意的是,《code>mail_parser 支持大量的扩展(UTF-8 头部、UTF-7 编码、续行、许多自定义字段等),并且比其他库更好地处理格式不正确的电子邮件。《strong>eml_codec
的目标是要开放贡献并随着时间的推移保持可维护性,这是通过解析器组合模式实现的,该模式鼓励编写小、可重用、可独立测试的函数。
rustyknife 使用与《code>eml_codec 相同的设计模式(解析器组合)和相同的库(《code>nom)。然而,《code>rustyknife 更针对 SMTP 服务器(MTA)而不是 IMAP(MDA)和电子邮件客户端(MUA)。因此,它只支持解析头部,而不是电子邮件的主体。一位熟人警告我,这个库有点慢,可能是因为它在解析电子邮件时进行了一些处理(例如重建和分配字符串)。如果这部分后续没有使用,那么分配/处理就被浪费了。《strong>eml_codec
的目标是尽可能少地进行处理以生成电子邮件的 AST,从而保持解析的高效性,然后在调用相应的函数时按需进行分配/处理。这通常被称为零拷贝。
支持
eml-codec
是 Aerogramme 项目 的一部分,通过 NGI Assure 基金获得资助,该基金由 NLnet 建立,并由欧盟委员会下一代互联网计划提供资金支持,在通信网络、内容和技术总司的赞助下,根据资助协议 No 957073。
许可证
eml-codec 版权 (C) 属于 eml-codec 贡献者
本程序是自由软件:您可以按照自由软件基金会发布的 GNU 通用公共许可证的条款重新分发和/或修改它,许可证版本为 3 或(根据您的选择)任何更高版本。
本程序分发时附带的是希望它可能是有用的,但没有任何保证;甚至没有隐含的适销性保证或适用于特定目的的适用性保证。有关详细信息,请参阅 GNU 通用公共许可证。
您应该已收到一份 GNU 通用公共许可证副本。如果没有,请参阅 http://www.gnu.org/licenses/。
依赖关系
~5.5MB
~160K SLoC