mail_struct : Minimalist Email Structure for Rust
mail_struct is a lightweight Rust library designed to define a clear and efficient structure for email messages. It provides optional integration with bitcode for efficient encoding/decoding and mail-send for SMTP transmission with domain-based grouping, making it a versatile choice for email handling in Rust applications.
Table of Contents
- Features
- Usage
- Design Philosophy
- Tech Stack
- Directory Structure
- API Documentation
- Historical Context
Features
- Core Structure: Defines
MailandUserMailstructs to represent email data. - Serialization: Optional
encodeanddecodefeatures usingbitcodefor high-performance binary serialization. - SMTP Integration: Optional
sendfeature with domain-based recipient grouping for efficient email delivery. - Type Safety: Leverages Rust's type system to ensure data integrity.
Usage
Add mail_struct to your Cargo.toml:
[]
= { = "0.1.10", = ["send", "encode", "decode"] }
Creating and Grouping Emails by Domain
use Mail;
async
Design Philosophy
The library follows a separation of concerns principle. The core lib.rs defines the data structures (Mail, UserMail), keeping the base dependency footprint minimal. Functionalities like serialization and sending are gated behind feature flags (encode, decode, send), allowing users to opt-in only for what they need.
When the send feature is active, the send.rs module implements IntoIterator for &Mail, returning MailMessage instances grouped by domain. This optimization reduces the number of SMTP connections needed and improves delivery efficiency. Additionally, MailMessage also implements IntoIterator, providing a zero-overhead fallback mechanism that ensures individual delivery to valid recipients when batch sending fails due to invalid recipient addresses.
Tech Stack
- Rust: Core language.
- xmail: Email validation and normalization.
- bitcode (Optional): For fast binary encoding and decoding.
- mail-send (Optional): For SMTP message construction and sending.
Directory Structure
.
├── Cargo.toml # Project configuration
├── README.md # Main documentation
├── readme # Documentation in specific languages
│ ├── en.md # English README
│ └── zh.md # Chinese README
├── src
│ ├── lib.rs # Core struct definitions and feature gates
│ └── send.rs # Domain grouping and SMTP message logic (feature: send)
└── tests
└── main.rs # Integration tests
API Documentation
struct Mail
Represents a basic email message.
sender_name: String: The user part of the sender's email address.sender_host: String: The domain part of the sender's email address.host_user_li: HashMap<String, HashSet<String>>: Recipients grouped by domain (host) with deduplicated user parts.body: Vec<u8>: The raw body content of the email.
Methods
new(sender: impl AsRef<str>, to_li: impl IntoIterator<Item = impl AsRef<str>>, body: impl Into<Vec<u8>>) -> Option<Self>
Creates a new Mail instance with automatic email processing:
- Normalization: Converts sender to lowercase and splits into user and domain.
- Validation: Uses
xmail::norm_user_hostto validate and normalize recipient addresses. - Filtering: Invalid email addresses are filtered out and logged.
- Deduplication: Recipients are automatically deduplicated using
HashSet. - Grouping: Recipients are organized by domain (host) for efficient processing.
- Return: Returns
Noneif no valid recipients remain after filtering.
Trait Implementations
IntoIterator for &'a Mail (requires send feature)
Implements IntoIterator for &Mail, returning a custom MailIter<'a> iterator.
- Domain Grouping: Automatically groups recipients by email domain, with each
MailMessagecontaining all recipients for the same domain. - Lazy Construction: The iterator lazily creates
MailMessageinstances during iteration, avoiding pre-allocation of aVec. - Efficient Delivery: Multiple recipients in the same domain can be delivered in a single SMTP transaction.
struct UserMail
A wrapper around Mail associating it with a user ID.
mail: Mail: The email content.user_id: u64: The unique identifier of the user associated with this mail.
struct MailMessage<'a> (requires send feature)
Represents an email grouped by recipient domain.
sender_name: &'a str: The user part of the sender's email address.sender_host: &'a str: The domain part of the sender's email address.domain: &'a str: The recipient domain name (e.g., "gmail.com").to_li: Vec<Address<'a>>: List of all recipient addresses for this domain.body: &'a [u8]: The email body content.
Trait Implementations
IntoMessage<'a>
Implements the mail_send::smtp::message::IntoMessage trait, allowing MailMessage to be directly converted into an SMTP message containing all recipients. This enables MailMessage to be passed directly to client.send() for batch sending.
Also implements IntoMessage for &MailMessage, allowing message creation without consuming ownership.
IntoIterator
Implements the IntoIterator trait, returning a custom MailMessageIter iterator.
- Zero Allocation: The iterator lazily constructs
Messageinstances during iteration, avoiding the overhead of creating an intermediateVec. - Fallback Strategy: Converts
MailMessageinto multiple individualMessageinstances (each containing one recipient). This is useful when batch sending fails, allowing for individual delivery to ensure valid recipients receive the email.
Historical Context
RFC 822 and the Separation of Envelope and Content
The design of email systems dates back to the early 1980s with the publication of RFC 822 (Standard for the Format of ARPA Internet Text Messages) and RFC 821 (Simple Mail Transfer Protocol). A key architectural decision was the separation of the "envelope" (handled by SMTP for routing) from the "content" (the message headers and body defined by RFC 822).
mail_struct honors this tradition by focusing on the structure of the message (the content), while delegating the transport (the envelope and transmission) to specialized libraries like mail-send. This modular approach mirrors the original design philosophy of the internet's most enduring communication protocol, ensuring flexibility and maintainability.
About
This project is an open-source component of js0.site ⋅ Refactoring the Internet Plan.
We are redefining the development paradigm of the Internet in a componentized way. Welcome to follow us:
mail_struct : 极简 Rust 邮件结构库
mail_struct 是一个轻量级的 Rust 库,旨在为邮件消息定义清晰且高效的结构。它提供了与 bitcode(用于高效编码/解码)和 mail-send(用于基于域名分组的 SMTP 传输)的可选集成,使其成为 Rust 应用中处理邮件的灵活选择。
目录
功能特性
- 核心结构: 定义了
Mail和UserMail结构体来表示邮件数据。 - 序列化: 通过
encode和decode特性支持使用bitcode进行高性能的二进制序列化。 - SMTP 集成: 可选的
send特性支持按域名分组收件人,实现高效的邮件投递。 - 类型安全: 利用 Rust 的类型系统确保数据完整性。
使用指南
在 Cargo.toml 中添加 mail_struct:
[]
= { = "0.1.10", = ["send", "encode", "decode"] }
创建并按域名分组邮件
use Mail;
async
设计理念
本库遵循关注点分离原则。核心 lib.rs 定义了数据结构(Mail, UserMail),保持基础依赖最小化。序列化和发送等功能通过特性标志(encode, decode, send)进行门控,允许用户仅按需开启。
当 send 特性激活时,send.rs 模块为 &Mail 实现了 IntoIterator,返回按域名分组的 MailMessage。这种优化减少了所需的 SMTP 连接数量并提高了投递效率。同时,MailMessage 也实现了 IntoIterator,提供了零开销的降级方案,确保在部分收件人地址错误导致批量发送失败时,仍能逐个投递给其他有效的收件人。
技术栈
- Rust: 核心开发语言。
- xmail: 邮箱验证和规范化。
- bitcode (可选): 用于快速二进制编码和解码。
- mail-send (可选): 用于构建和发送 SMTP 消息。
目录结构
.
├── Cargo.toml # 项目配置
├── README.md # 主文档
├── readme # 多语言文档
│ ├── en.md # 英文 README
│ └── zh.md # 中文 README
├── src
│ ├── lib.rs # 核心结构定义及特性门控
│ └── send.rs # 域名分组及 SMTP 消息逻辑 (特性: send)
└── tests
└── main.rs # 集成测试
API 文档
struct Mail
表示一个基础的邮件消息。
sender_name: String: 发件人邮箱地址的用户部分。sender_host: String: 发件人邮箱地址的域名部分。host_user_li: HashMap<String, HashSet<String>>: 按域名(主机)分组的收件人,用户部分已去重。body: Vec<u8>: 邮件的原始正文内容。
方法
new(sender: impl AsRef<str>, to_li: impl IntoIterator<Item = impl AsRef<str>>, body: impl Into<Vec<u8>>) -> Option<Self>
创建新的 Mail 实例,自动处理邮箱:
- 规范化:将发件人转换为小写并拆分为用户和域名。
- 验证:使用
xmail::norm_user_host验证和规范化收件人地址。 - 过滤:过滤掉无效的邮箱地址并记录日志。
- 去重:使用
HashSet自动去除重复的收件人。 - 分组:按域名(主机)组织收件人,提高处理效率。
- 返回:如果过滤后没有有效收件人,则返回
None。
Trait 实现
IntoIterator for &'a Mail (需要 send 特性)
为 &Mail 实现了 IntoIterator,返回自定义的 MailIter<'a> 迭代器。
- 按域名分组:自动按邮件域名分组收件人,每个
MailMessage包含同一域名的所有收件人。 - 惰性构造:迭代器在遍历时惰性创建
MailMessage实例,避免预先分配Vec。 - 高效投递:同一域名的多个收件人可以在单个 SMTP 事务中投递。
struct UserMail
Mail 的包装器,将其与用户 ID 关联。
mail: Mail: 邮件内容。user_id: u64: 与此邮件关联的用户的唯一标识符。
struct MailMessage<'a> (需要 send 特性)
表示按收件人域名分组的邮件。
sender_name: &'a str: 发件人邮箱地址的用户部分。sender_host: &'a str: 发件人邮箱地址的域名部分。domain: &'a str: 收件人域名(例如 "gmail.com")。to_li: Vec<Address<'a>>: 该域名下的所有收件人地址列表。body: &'a [u8]: 邮件正文内容。
Trait 实现
IntoMessage<'a>
实现了 mail_send::smtp::message::IntoMessage trait,允许 MailMessage 直接转换为包含所有收件人的 SMTP 消息。这使得 MailMessage 可以直接传递给 client.send() 进行批量发送。
同时为 &MailMessage 实现了 IntoMessage,允许在不消耗所有权的情况下创建消息。
IntoIterator
实现了 IntoIterator trait,返回自定义的 MailMessageIter 迭代器。
- 零分配:迭代器在遍历时惰性构造
Message,避免了创建中间Vec的开销。 - 降级策略:将
MailMessage转换为多个独立的Message(每个包含一个收件人)。这在批量发送失败时非常有用,可以逐个投递以确保有效地址的收件人能收到邮件。
历史背景
RFC 822 与信封/内容的分离
电子邮件系统的设计可以追溯到 20 世纪 80 年代初 RFC 822(ARPA 互联网文本消息格式标准)和 RFC 821(简单邮件传输协议)的发布。一个关键的架构决策是将"信封"(由 SMTP 处理用于路由)与"内容"(由 RFC 822 定义的消息头和正文)分离开来。
mail_struct 秉承了这一传统,专注于消息的结构(内容),而将传输(信封和发送)委托给像 mail-send 这样的专用库。这种模块化的方法反映了互联网最持久通信协议的原始设计哲学,确保了灵活性和可维护性。
关于
本项目为 js0.site ⋅ 重构互联网计划 的开源组件。
我们正在以组件化的方式重新定义互联网的开发范式,欢迎关注: