Skip to content

tio-mail-wing简介 ​

核心目标 ​

  1. 实现邮件接收服务 (SMTP):能够接收来自其他邮件服务器(如 QQ、Gmail 发来的邮件)或邮件客户端(如 Foxmail、Outlook 发出的邮件)的邮件。
  2. 实现邮件读取服务 (POP3/IMAP):允许邮件客户端(如 QQ 邮箱 App、Gmail App、Thunderbird)连接到我们的服务器,拉取和管理邮件。
  3. 用户和邮箱管理:管理自己服务器上的邮箱账户和密码。
  4. 邮件存储:持久化存储接收到的邮件。

开发规划 ​

第一阶段:项目初始化与基础架构 ​

这是万里长征的第一步,搭建好骨架。

  1. 创建 tio-boot 项目
    • 使用 Maven 创建一个标准的 tio-boot 项目。
    • 在 pom.xml 中引入核心依赖:
      xml
```
  1. 配置服务器端口 在 app.properties 中规划好标准端口。
    properties

mail.server.smtp.port=25 mail.server.smtp.heartbeat-timeout=60000 mail.server.pop3.port=110 mail.server.pop3.heartbeat-timeout=60000 mail.server.imap.port=143 mail.server.imap.heartbeat-timeout=60000 ```


第二阶段:实现核心协议 (由简到难) ​

邮件协议是基于文本的、一问一答式的。tio-boot 的 AioHandler 就是处理这些问答的核心。

通用准备:

  • 编解码器:邮件协议都是基于行(以 \r\n 结尾)的。需要一个简单的字符串编解码器。
  • 会话上下文:使用 ChannelContext 的自定义子类(如 SmtpSessionContext)来跟踪每个客户端连接的状态(例如:是否已认证、MAIL FROM 命令是否已发送等)。

任务1:实现 POP3 服务 (最简单,先做) ​

POP3 协议简单,状态少,适合入门。

  1. 创建 Pop3ServerAioHandler and Pop3SessionContext and Pop3ServerAioListener
    • 在 handler 方法中,接收客户端发来的一行命令(如 USER a@b.com, PASS 123, STAT, LIST, RETR 1, DELE 1, QUIT)。
    • 使用 if-else 或 switch 解析命令。
    • 响应格式:成功响应以 +OK 开头,失败响应以 -ERR 开头。
  2. 实现命令逻辑
    • USER/PASS: 调用 UserService 进行认证。认证成功后,在会话上下文中标记为“已登录”。
    • STAT: 调用 MailService 获取邮箱中的邮件数量和总大小。
    • LIST: 遍历邮箱中的所有邮件,返回每封邮件的编号和大小。
    • RETR [msg_id]: 调用 MailService 读取指定邮件的完整内容(包括头和体),并发送给客户端。
    • DELE [msg_id]: 在会话中标记邮件为待删除。
    • QUIT: 退出,关闭连接。
  3. 测试
    • 工具:使用 telnet localhost 110 手动测试命令。
    • 客户端:配置 Foxmail 或 Thunderbird 客户端,使用 POP3 协议连接的服务器。

任务2:实现 SMTP 服务 (核心接收功能) ​

SMTP 协议状态机比 POP3 复杂。

  1. 创建 SmtpServerAioHandler 等相关类
    • 处理的命令包括:HELO/EHLO, AUTH LOGIN, MAIL FROM:<...>, RCPT TO:<...>, DATA, QUIT。
  2. 实现命令逻辑 (状态流转)
    • 连接建立:服务器发送 220 tio-mail-wing ESMTP Service ready。
    • HELO/EHLO: 客户端问候。服务器响应 250 OK。
    • AUTH LOGIN: 进行认证。这是客户端发信时必须的。需要处理 Base64 编码的用户名和密码。
    • MAIL FROM: 记录发件人。在会话上下文中保存。
    • RCPT TO: 记录收件人。检查收件人是否是本服务器的用户。可以有多个 RCPT TO。
    • DATA: 客户端告知要开始发送邮件内容了。服务器响应 354 Start mail input; end with <CRLF>.<CRLF>。
    • 邮件内容接收:进入特殊模式,持续接收数据,直到遇到单独一行的 . 为止。
    • 邮件解析与存储:将接收到的完整邮件内容(一坨字符串)交给 angus-mail (Jakarta Mail) 的 MimeMessage 解析,然后调用 MailService 存入收件人的邮箱。
    • 存储成功后:响应 250 OK: queued as ...。
    • QUIT: 关闭连接。
  3. 测试
    • 工具:telnet localhost 25。
    • 客户端:配置 Foxmail/Outlook,使用的服务器作为 SMTP 服务器向外发信(或给自己发信)。
    • 外部服务器:从的 QQ 邮箱或 Gmail 向在 tio-mail-wing 上创建的账户(如 user@yourdomain.com)发送一封邮件,看能否成功接收。

任务3:实现 IMAP 服务 (最复杂,最后做) ​

IMAP 功能强大,但协议也最复杂,是有状态的,且命令繁多。

  1. 创建 ImapServerAioHandler
    • IMAP 命令有标签(Tag),如 A001 LOGIN user pass。响应时也需要带上相同的标签,如 A001 OK LOGIN completed。
  2. 实现核心命令
    • CAPABILITY: 告诉客户端服务器支持哪些功能。
    • LOGIN: 认证。
    • SELECT [mailbox]: 选择邮箱(如 INBOX)。这是大部分操作的前提。
    • FETCH [msg_id] (FLAGS|BODY[HEADER]|BODY[TEXT]): 获取邮件信息,可以只获取标志、头、正文等部分内容,非常灵活。
    • STORE [msg_id] +FLAGS (\Seen): 修改邮件标志,如标记为已读。
    • LOGOUT: 退出。
  3. 挑战
    • IMAP 的状态管理非常复杂。
    • FETCH 命令的参数组合非常多。
    • 需要支持邮件夹(Mailbox)的概念。
  4. 建议
    • 先实现最核心的 LOGIN, SELECT INBOX, FETCH, LOGOUT,让客户端能连上并看到邮件列表和内容。
    • 仔细阅读 RFC 3501 (IMAP4rev1) 文档。

第三阶段:数据持久化与业务逻辑 ​

  1. 用户管理 (UserService)

    • 初期:可以用一个简单的 Map 或配置文件(如 users.properties)来存储用户名和密码。
    • 进阶:使用数据库(如 postgresql)来存储用户信息,方便管理。
  2. 邮件存储 (MailService / MailRepository)

    • 推荐方案:Maildir 格式
      • 这是一种工业标准的、基于文件系统的邮件存储格式。
      • 每个用户一个主目录,下面有 cur, new, tmp 三个子目录。
      • 每封邮件一个文件,文件名保证唯一,避免了文件锁,性能好,结构清晰。
      • MailService 的职责就是根据用户名找到对应的目录,在其中创建、读取、移动(如从未读 new 到已读 cur)、删除文件。
    • 进阶方案:数据库
      • 可以将邮件元数据(发件人、主题、时间等)存入数据库表,邮件原文(MIME 内容)可以存为 BLOB/TEXT 字段或依然存在文件系统。
      • 管理和搜索方便,但大邮件的存取可能有效率问题。

第四阶段:安全与部署 ​

  1. 实现 SSL/TLS (STARTTLS)

    • 现代邮件客户端默认都要求加密连接。不加这个,QQ、Gmail 客户端很可能连不上。
    • 邮件协议的加密通过 STARTTLS 命令实现。客户端发送此命令后,服务器需要将当前连接升级为 SSL/TLS 连接。
    • tio-boot 支持 SSL/TLS。需要在 AioHandler 中捕获 STARTTLS 命令,然后调用 Tio.startSSL(channelContext, ...) 方法来升级连接。
    • 需要一个 SSL 证书(开发阶段可以使用自签名证书)。
    • 安全端口:除了标准端口,还应支持隐式 SSL 端口(SMTPS: 465, POP3S: 995, IMAPS: 993)。这需要在 tio-boot 中配置单独的、启用 SSL 的 TioServer 实例。
  2. 部署

    • 使用 Maven 打包成一个可执行的 jar 文件。
    • 在服务器上通过 java -jar tio-mail-wing.jar 运行。
    • 为了让公网能访问,需要一台有公网 IP 的服务器,并配置好域名和 DNS(MX 记录指向的服务器 IP)。

总结与建议 ​

  1. 分步走,先主后次:POP3 -> SMTP -> IMAP。先让一个协议跑通,再做下一个。
  2. 测试驱动:每实现一个命令,就用 telnet 测试一下,确保输入输出符合预期。
  3. 日志是生命线:在 AioHandler 的每个关键步骤打印详细日志,包括收到的命令和发出的响应。当客户端连接失败时,日志是唯一的排错线索。
  4. 阅读 RFC 文档:虽然枯燥,但邮件协议的细节都在 RFC 文档里。遇到不解的行为时,查阅 RFC 是最权威的方式。
    • SMTP: RFC 5321
    • POP3: RFC 1939
    • IMAP: RFC 3501
  5. 参考开源实现:可以参考一些优秀的开源邮件服务器项目,如 James (Java), Dovecot (C) 的设计思想,但不要陷入代码细节。

MIT Licensed