Skip to main content
Glama
leeguooooo
by leeguooooo
UID_FIXES_COMPLETED.md5.79 kB
# UID 修复完成总结 ## 修复时间 2025-10-16 ## 问题描述 ### 1. NoneType 错误(已修复 ✅) - **问题**:`get_email_detail` 在邮件已删除时崩溃 - **原因**:没有检查 `data` 是否为 None - **修复**:添加完整的空值检查 ### 2. UID/序列号混淆(已修复 ✅) - **问题**:`search_emails` 返回 UID,但所有操作函数把它当序列号使用 - **原因**:`get_email_detail`、`mark_email_read`、`delete_email`、`move_email_to_trash` 都只支持序列号 - **结果**:搜索后的操作会作用于错误的邮件("去哪儿网" vs "地上铁招聘") ## 已完成的修复 ### 1. `get_email_detail` ✅ **文件**:`src/legacy_operations.py:292-422` **改进**: - 优先尝试 UID:`mail.uid('fetch', email_id, '(RFC822 FLAGS)')` - 失败时回退到序列号:`mail.fetch(email_id, '(RFC822 FLAGS)')` - 添加详细的空值检查 - 返回结果包含 `uid` 字段(如果使用了 UID) - 添加 debug 日志记录使用了哪种方式 **向后兼容**: - ✅ 旧代码传递序列号仍然工作 - ✅ 新代码传递 UID 也工作 - ✅ 自动检测并使用正确的方法 ### 2. `mark_email_read` ✅ **文件**:`src/legacy_operations.py:424-454` **改进**: - 优先尝试 UID:`mail.uid('store', email_id, '+FLAGS', '\\Seen')` - 失败时回退到序列号 - 添加 debug 日志 ### 3. `delete_email` ✅ **文件**:`src/legacy_operations.py:456-487` **改进**: - 优先尝试 UID:`mail.uid('store', email_id, '+FLAGS', '\\Deleted')` - 失败时回退到序列号 - 保持 expunge 清理 ### 4. `move_email_to_trash` ✅ **文件**:`src/legacy_operations.py:489-542` **改进**: - copy 操作:优先 UID,回退序列号 - store 操作:优先 UID,回退序列号 - 处理垃圾箱不存在的情况 ## 技术细节 ### UID vs 序列号 **UID (Unique Identifier)**: - ✅ 稳定:删除其他邮件后不变 - ✅ `search_emails` 返回的是 UID - ✅ 跨会话保持一致 - ❌ 某些 IMAP 服务器可能不支持 **序列号 (Sequence Number)**: - ✅ 所有 IMAP 服务器都支持 - ❌ 不稳定:删除邮件后会重新编号 - ❌ `list_emails` 返回的是序列号 ### 检测逻辑 ```python # 1. 确保是字符串 if isinstance(email_id, int): email_id = str(email_id) # 2. 对于数字 ID,优先尝试 UID if email_id and str(email_id).isdigit(): # 尝试 UID result, data = mail.uid('fetch', email_id, ...) # 检查是否成功 if result == 'OK' and data and data[0]: # 成功 used_uid = True else: # 失败,回退到序列号 result, data = mail.fetch(email_id, ...) else: # 非数字 ID,直接使用序列号 result, data = mail.fetch(email_id, ...) ``` ### 回退机制 所有函数都实现了相同的模式: 1. 如果是数字 ID,尝试 UID 命令 2. 检查响应:`result == 'OK' and data and data[0] and data[0] not in (None, b'')` 3. 如果失败,记录 debug 日志并尝试序列号命令 4. 继续处理 ## 测试建议 ### 测试场景 1:搜索后获取详情 ```bash # 1. 搜索邮件 search_emails(query="test") # 返回:[{"id": "1186", "subject": "地上铁招聘", ...}] # 2. 获取详情 get_email_detail(email_id="1186") # ✅ 应该返回"地上铁招聘"的详情,而不是其他邮件 ``` ### 测试场景 2:list 后获取详情 ```bash # 1. 列出邮件 list_emails(limit=10) # 返回:[{"id": "1", "subject": "...", ...}] # 2. 获取详情 get_email_detail(email_id="1") # ✅ 应该返回第1封邮件的详情 ``` ### 测试场景 3:UID 操作 ```bash # 1. 搜索邮件 search_emails(query="test") # 返回:[{"id": "1186", ...}] # 2. 标记为已读 mark_email_read(email_id="1186") # ✅ 应该成功,不报错 # 3. 删除邮件 delete_email(email_id="1186") # ✅ 应该删除正确的邮件 ``` ## 还未修复的问题 ### 1. 批量操作(中等优先级) 以下函数仍然需要 UID 支持: - `batch_move_to_trash` - `batch_delete_emails` - `batch_mark_read` **计划**:应用相同的 UID 优先 + 回退模式 ### 2. 性能问题(高优先级) `fetch_emails` 使用 `(RFC822)` 下载完整邮件: ```python # 当前(慢): result, data = mail.fetch(email_id, '(RFC822)') # 下载所有内容 # 应改为(快): result, data = mail.fetch(email_id, '(BODY.PEEK[HEADER.FIELDS (From Subject Date)] FLAGS)') # 只获取头部 ``` **预期改进**: - 当前:50封邮件 ~10-15秒 - 优化后:50封邮件 ~2-3秒 ### 3. Sync DB 未使用(低优先级) `email_sync.db` 有数据但未被查询,所有操作仍然实时访问 IMAP。 ## 验证清单 - [x] `get_email_detail` 支持 UID - [x] `mark_email_read` 支持 UID - [x] `delete_email` 支持 UID - [x] `move_email_to_trash` 支持 UID - [x] 添加了空值检查防止崩溃 - [x] 添加了 debug 日志 - [x] 语法检查通过 - [ ] 批量操作支持 UID(待完成) - [ ] 性能优化(待完成) - [ ] 使用 Sync DB(待完成) ## 迁移说明 ### 对现有代码的影响 - ✅ **零破坏性**:所有修改都是向后兼容的 - ✅ 序列号仍然工作 - ✅ UID 现在也工作 - ✅ 自动选择正确的方法 ### 客户端代码无需修改 ```python # 这两种方式都能正确工作: get_email_detail(email_id="1") # 序列号 get_email_detail(email_id="1186") # UID # 响应现在包含 uid 字段(如果使用了 UID): { "id": "1186", "uid": "1186", # 新增字段 "subject": "...", ... } ``` ## 日志示例 修复后,你会看到这样的日志: ``` DEBUG - Successfully fetched email using UID 1186 DEBUG - UID store failed for 999, trying sequence number ``` 这些日志帮助理解每次使用了哪种方法。

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/leeguooooo/email-mcp-service'

If you have feedback or need assistance with the MCP directory API, please join our Discord server