Commit Graph
2 Commits
Author SHA1 Message Date
dsh 3a4636c2c5 fix(imap): FETCH BODY/BODYSTRUCTURE 解析失败时服务器 panic 导致客户端只能取到部分邮件
根因: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
2026-08-19 08:52:39 -04:00
kevin 07ba01a6f6 fix(imap): 修复 Thunderbird 未读状态丢失(SQLite 并发写 + 客户端 seq 错位)
A. SQLite 并发写失败被吞(高概率根因):
- DSN 追加 _busy_timeout=5000&_journal_mode=WAL&_synchronous=NORMAL,
  WAL 下读不阻塞写,消除瞬时 SQLITE_BUSY
- UpdateMessagesFlags 不再吞 MarkReadState/MarkFlagged 错误:
  出错记日志并返回 error(客户端收到 NO 会重试)
- Web MarkRead/Delete 同款静默丢错补日志

B. 客户端 seq 视图错位(集成测试复现后修复):
- 真实服务器+脚本客户端测试复现:客户端按日期倒序自编号发
  seq 式 STORE 时,旧排序(id ASC)把最旧邮件标为已读
- 规范排序改为 date DESC, id DESC(最新在前),与主流客户端
  默认视图一致;buildNewMessageUpdate 改用 seqOf 取真实序号
- 新增 UID STORE / 服务器下发 seq STORE / 自编号 seq STORE 集成测试

注:go-imap v1.2.1 存在库内 *conn.silent() 数据竞争(启用推送后
必然触发),集成测试以 //go:build !race 排除,-race 下由单元测试
覆盖推送逻辑
2026-08-19 20:30:06 +08:00