fix(imap): FETCH BODY/BODYSTRUCTURE 解析失败时服务器 panic,客户端只能取到部分邮件 #10

Merged
kevin merged 1 commits from dsh/mailgo:fix/imap-fetch-body-panic into main 2026-08-19 20:55:23 +08:00
Contributor

问题现象

  • Thunderbird 同步只能取到 4 封邮件,无法获取全部
  • 手机客户端一直卡在「正在获取邮件」

根因

backendutil.FetchBodyStructure 对两类消息返回 nil,buildIMAPMessage 未处理 nil,go-imap 在 send() 协程格式化 FETCH 响应时 nil 指针解引用 panic,连接中途断开:

  1. base64 编码的 message/rfc822 附件(转发邮件场景):库内不解码 transfer-encoding,把 base64 文本当嵌套消息头解析 → malformed MIME header line 错误。实测生产数据 kevin INBOX id=58、dsh Sent id=59(由 .mail-monitor/forward.py 生成)
  2. 截断的 multipart(缺少结束边界):BODYSTRUCTURE(extended) 解析报 multipart: NextPart: EOF。实测 ~25 封 go_blog/Gitea 通知邮件受影响

修复

  • internal/imap_server/backend.go
    • BodyStructure 解析失败时降级为 text/plain 单段结构,杜绝 nil panic
    • FetchBodySection 返回 nil 时跳过该 section,不再写入 nil literal
  • internal/imap_server/integration_test.go:新增 TestFetchBodyMalformedMIME 回归测试(覆盖 base64 rfc822 附件 + 截断 multipart)

验证

  • 回归测试:无修复时精确复现 panic,有修复时通过
  • 数据库副本 + 真实 IMAP 服务器全量验证:kevin INBOX 60/60、Sent 31/31、dsh INBOX 18/18、Sent 24/24(含 BODY/BODYSTRUCTURE)
  • 生产环境已部署验证(dsh INBOX/Sent 全量取回,服务无 panic)
## 问题现象 - Thunderbird 同步只能取到 4 封邮件,无法获取全部 - 手机客户端一直卡在「正在获取邮件」 ## 根因 `backendutil.FetchBodyStructure` 对两类消息返回 nil,`buildIMAPMessage` 未处理 nil,go-imap 在 `send()` 协程格式化 FETCH 响应时 nil 指针解引用 panic,连接中途断开: 1. **base64 编码的 message/rfc822 附件**(转发邮件场景):库内不解码 transfer-encoding,把 base64 文本当嵌套消息头解析 → `malformed MIME header line` 错误。实测生产数据 kevin INBOX id=58、dsh Sent id=59(由 .mail-monitor/forward.py 生成) 2. **截断的 multipart**(缺少结束边界):BODYSTRUCTURE(extended) 解析报 `multipart: NextPart: EOF`。实测 ~25 封 go_blog/Gitea 通知邮件受影响 ## 修复 - `internal/imap_server/backend.go`: - BodyStructure 解析失败时降级为 text/plain 单段结构,杜绝 nil panic - FetchBodySection 返回 nil 时跳过该 section,不再写入 nil literal - `internal/imap_server/integration_test.go`:新增 `TestFetchBodyMalformedMIME` 回归测试(覆盖 base64 rfc822 附件 + 截断 multipart) ## 验证 - 回归测试:无修复时精确复现 panic,有修复时通过 - 数据库副本 + 真实 IMAP 服务器全量验证:kevin INBOX 60/60、Sent 31/31、dsh INBOX 18/18、Sent 24/24(含 BODY/BODYSTRUCTURE) - 生产环境已部署验证(dsh INBOX/Sent 全量取回,服务无 panic)
dsh added 1 commit 2026-08-19 20:54:55 +08:00
根因:backendutil.FetchBodyStructure 对部分消息返回 nil(典型场景:
- message/rfc822 附件为 base64 编码时库内不解码,把编码文本当嵌套
  消息头解析报错(转发邮件场景,如 .mail-monitor/forward.py 转发)
- multipart 缺少结束边界(截断)时 extended 解析报错)

buildIMAPMessage 未处理 nil,go-imap 格式化 FETCH 响应时在 send()
协程 nil 指针解引用 panic,连接中断——Thunderbird 只取到崩溃前已
发送的几封邮件,手机客户端一直卡在"正在获取邮件"。

修复:
- BodyStructure 解析失败时降级为 text/plain 单段结构,杜绝 nil
- FetchBodySection 返回 nil 时跳过该 section,不再写入 nil literal
- 新增集成测试 TestFetchBodyMalformedMIME 覆盖两类畸形 MIME
kevin merged commit f8fbe1ebdb into main 2026-08-19 20:55:23 +08:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: kevin/mailgo#10