增加duckmail支持

This commit is contained in:
rockxsj
2026-03-19 16:41:30 +08:00
parent 93ab984200
commit 91120a2fb4
15 changed files with 1294 additions and 47 deletions

View File

@@ -0,0 +1,77 @@
# DuckMail 邮箱服务设计说明
**目标:** 为系统新增独立的 `duck_mail` 邮箱服务类型,支持在邮箱服务管理页配置 DuckMail并在注册页选择该服务进行注册。
## 背景
当前项目已有三类邮箱服务:
- `tempmail`:公共临时邮箱
- `custom_domain`MoeMail 风格 REST API
- `temp_mail`:自部署 Cloudflare Worker 临时邮箱
DuckMail 的接口模型与 `custom_domain` 不兼容。它采用 `/accounts``/token``/messages` 资源模型,并通过 Bearer Token 或 API Key 访问。因此需要新增独立服务类型,而不是复用现有 `custom_domain` 实现。
## 设计决策
### 1. 独立服务类型
新增 `duck_mail` 枚举值、服务类、前后端配置项与注册页可见性逻辑,避免与现有 MoeMail 接口混淆。
### 2. 配置模型
DuckMail 仅支持手动填写默认域名,不预拉取 `/domains`,配置项如下:
- `base_url`DuckMail API 地址
- `default_domain`:默认域名,创建邮箱时直接拼接
- `password_length`:自动创建 DuckMail 账户时使用的随机密码长度
- `api_key`:可选,私有域名时通过 `Authorization: Bearer dk_xxx` 调用
- `timeout`
- `max_retries`
- `proxy_url`
### 3. 创建邮箱流程
DuckMail 服务在 `create_email()` 中:
1. 生成合法用户名(至少 3 个字符)
2.`default_domain` 拼接邮箱地址
3. 生成随机密码
4. 调用 `POST /accounts`
5. 调用 `POST /token` 获取 Bearer Token
6. 返回 `email``service_id``account_id``token`、内部随机密码等信息
### 4. 取验证码流程
DuckMail 的列表接口不返回正文,需:
1. 轮询 `GET /messages`
2. 筛选 OpenAI 邮件
3. 对新消息调用 `GET /messages/{id}`
4.`text/html` 中提取验证码
### 5. 删除与健康检查
- `delete_email()`:使用账户 Bearer Token 调 `DELETE /accounts/{id}`
- `check_health()`:优先调 `GET /domains`;如果配置了私有域名 API Key也沿用相同入口
### 6. 前端接入
邮箱服务管理页新增 DuckMail 子类型:
- 列表中单独展示为 DuckMail
- 新建/编辑表单展示 DuckMail 专属字段
注册页:
-`/registration/available-services` 中显示 DuckMail 服务
- 选择后与其他数据库邮箱服务一样传递 `email_service_type=duck_mail``email_service_id`
## 测试范围
至少覆盖:
- DuckMail `create_email()` 会调用账户创建与 token 获取
- DuckMail `get_verification_code()` 会按“列表 -> 详情”提取验证码
- 注册接口的可用服务列表包含 `duck_mail`
- 邮箱服务类型接口与敏感字段过滤支持 `duck_mail`

View File

@@ -0,0 +1,151 @@
# DuckMail 邮箱服务实现计划
> **给 Codex** 必须按 TDD 执行本计划,先写失败测试,再写最小实现。
**目标:** 新增独立 `duck_mail` 邮箱服务类型,支持 DuckMail 配置、测试、注册可见性与实际验证码拉取。
**架构:** 在现有 `BaseEmailService` 体系中新增 `DuckMailService`,并把它接入服务工厂、邮箱服务管理 API、注册可用服务 API 与前端页面。DuckMail 不复用 `custom_domain` 逻辑,单独维护请求头、创建邮箱、登录取 token、拉取消息与删除账户逻辑。
**技术栈:** Python、FastAPI、SQLAlchemy、原生 JavaScript、pytest
---
### 任务 1补 DuckMail 服务层测试
**文件:**
- 新建:`tests/test_duck_mail_service.py`
- 参考:`src/services/temp_mail.py`
- 参考:`src/services/moe_mail.py`
**步骤 1写失败测试**
- 测试 `create_email()`
- 会先调用 `POST /accounts`
- 再调用 `POST /token`
- 返回值包含 `email``service_id``account_id``token`
- 测试 `get_verification_code()`
- 先调 `GET /messages`
- 再调 `GET /messages/{id}`
- 能从正文提取 6 位验证码
**步骤 2运行失败测试**
运行:`pytest tests/test_duck_mail_service.py -q`
预期:因为 `DuckMailService` 尚不存在而失败。
**步骤 3写最小实现**
- 新增 `src/services/duck_mail.py`
- 只实现本轮测试所需的最小方法:
- 初始化配置
- 请求封装
- 创建邮箱
- 获取 token
- 拉取消息与验证码
- 删除账户
- 健康检查
**步骤 4运行测试确认通过**
运行:`pytest tests/test_duck_mail_service.py -q`
### 任务 2补服务枚举与工厂接入测试
**文件:**
- 新建:`tests/test_email_service_duckmail_routes.py`
- 修改:`src/config/constants.py`
- 修改:`src/services/__init__.py`
**步骤 1写失败测试**
- 断言 `EmailServiceType("duck_mail")` 可用
- 断言 `EmailServiceFactory.get_service_class(EmailServiceType.DUCK_MAIL)` 已注册
**步骤 2运行失败测试**
运行:`pytest tests/test_email_service_duckmail_routes.py::test_duck_mail_service_registered -q`
**步骤 3写最小实现**
- 在枚举中加入 `DUCK_MAIL`
- 在服务工厂注册 `DuckMailService`
**步骤 4运行测试确认通过**
运行:`pytest tests/test_email_service_duckmail_routes.py::test_duck_mail_service_registered -q`
### 任务 3补邮箱服务 API 与注册可见性测试
**文件:**
- 修改:`src/web/routes/email.py`
- 修改:`src/web/routes/registration.py`
- 参考:`src/database/models.py`
**步骤 1写失败测试**
- 测试邮箱服务类型接口包含 `duck_mail`
- 测试敏感配置过滤支持 `api_key`
- 测试 `/registration/available-services` 会返回 `duck_mail`
**步骤 2运行失败测试**
运行:`pytest tests/test_email_service_duckmail_routes.py -q`
**步骤 3写最小实现**
- `email.py`
- 统计增加 `duck_mail_count`
- `get_service_types()` 增加 DuckMail 配置项
- `registration.py`
- `available-services` 增加 `duck_mail`
- `_normalize_email_service_config()` 支持 DuckMail 字段
- `_run_sync_registration_task()` 支持 DuckMail 默认选择逻辑
**步骤 4运行测试确认通过**
运行:`pytest tests/test_email_service_duckmail_routes.py -q`
### 任务 4补前端 DuckMail 配置与注册入口
**文件:**
- 修改:`templates/email_services.html`
- 修改:`static/js/email_services.js`
- 修改:`static/js/app.js`
- 可选修改:`templates/index.html`
**步骤 1先补最小前端逻辑**
- 邮箱服务页新增 DuckMail 类型展示与新建/编辑字段
- 注册页邮箱服务下拉新增 DuckMail 分组
- 选择 DuckMail 时传 `duck_mail:<id>`
**步骤 2人工自检**
- 检查新增字段是否与后端字段名一致:
- `base_url`
- `api_key`
- `default_domain`
- `password_length`
### 任务 5完整验证
**文件:**
- 修改:`README.md`
**步骤 1补文档**
- 在功能列表与邮箱服务说明中加入 DuckMail
**步骤 2运行完整验证**
运行:`pytest tests/test_duck_mail_service.py tests/test_email_service_duckmail_routes.py -q`
如环境允许,再运行:
`python -m compileall src`
**步骤 3检查结果**
- 确认 pytest 退出码为 0
- 确认编译检查无语法错误