feat: 重构配置文件格式并添加 IMAP ID 命令支持

- 配置文件分离:用户配置与项目配置分离,项目级配置(客户端信息、需要 ID 命令的 provider)放在代码中
- 新增 check_id 字段:用户可选择禁用单个账户的 ID 命令发送
- 简化 provider:只保留 163 和 QQ,移除未使用的 Gmail/Outlook/188 等
- 修复 163 邮箱收件箱问题:通过发送 IMAP ID 命令解决 Unsafe Login 错误

BREAKING CHANGE: 配置文件格式变化,旧配置不兼容
This commit is contained in:
2026-04-10 00:39:06 +08:00
parent d54fd01001
commit 52c5eb5ae8
7 changed files with 334 additions and 200 deletions

View File

@@ -10,20 +10,47 @@
## 讨论内容
### 简化方案
用户建议采用简化配置:
### 最终配置格式
```yaml
from:
account: work # 通过 name 引用账户
defaults:
encryption: ssl
insecure: false
unsafe_html: false
signature: ""
accounts:
- name: "工作邮箱"
email: "user@163.com"
provider: "163" # 自动填充 imap/smtp
username: "user@163.com" # 统一认证
password: "xxx"
smtp_encryption: "ssl" # 可选
- name: work
email: foolsecret@163.com
provider: 163
username: foolsecret@163.com
password: xxx
imap:
host: imap.163.com
port: 993
encryption: ssl
insecure: false
smtp:
host: smtp.163.com
port: 465
encryption: ssl
insecure: false
```
### 配置说明
| 字段 | 说明 |
|------|------|
| `from.account` | 通过账户的 `name` 引用默认发件账户 |
| `defaults.encryption` | 全局默认加密类型 (`ssl`/`starttls`/`none`) |
| `defaults.insecure` | 全局默认跳过 TLS 证书验证 |
| 账户内覆盖 | 可以在单个账户的 imap/smtp 内覆盖默认值 |
### 自动识别逻辑
1. **自动识别 Provider**: 通过邮箱后缀自动判断
@@ -33,35 +60,26 @@ accounts:
- `@outlook.com` / `@office365.com` → Outlook
- 其他 → custom
2. **Provider 不匹配时**: 视为 custom需手动配置 host/port
2. **自动填充**: 根据 provider 自动填充 imap/smtp 的 host/port/encryption
### Onboarding 流程
3. **统一认证**: username/password 只需在账户顶层配置,会自动复制到 IMAP 和 SMTP
```
1. 输入邮箱地址
2. 自动识别 provider
3. ┌─ 已知服务商 → 显示默认配置,提示确认
└─ 自定义邮箱 → 提示手动配置 IMAP/SMTP
4. 输入密码
5. 保存配置
```
### 向后兼容
**不兼容旧版配置**,需要用户重新配置。
## 实现计划
| 步骤 | 文件 | 修改内容 |
|------|------|---------|
| 1 | config.go | 新增 Provider、SMTPEncryption 字段 |
| 2 | config.go | 添加 normalizeAccount() 自动填充默认值 |
| 3 | config.go | 添加 providerDefaults 映射表 |
| 4 | config.go | 修改 getAccounts() 调用 normalize |
| 5 | onboarding.go | 修改交互流程,支持自动识别和默认值 |
| 1 | config.go | 新增 FromConfig 和 DefaultsConfig 结构 |
| 2 | config.go | 修改 normalizeAccount() 支持 defaults |
| 3 | config.go | 新增 getDefaultFromEmail() 和 getDefaultAccount() |
| 4 | main.go | 使用新函数获取默认账户信息 |
| 5 | 测试 | 验证配置读取和发送功能 |
## 待处理
## 已完成
- [ ] 实现 config.go 修改
- [ ] 实现 onboarding.go 流程调整
- [x] 实现 config.go 修改
- [x] 实现 main.go 逻辑调整
- [ ] 测试配置读取和写入

View File

@@ -0,0 +1,102 @@
# 项目配置与用户配置分离讨论
**日期**: 2026-04-10
## 背景
在实现 IMAP ID 命令功能时需要在连接时发送客户端身份信息。这些信息name、version、vendor属于**应用开发配置**,而非用户运行时配置。
如果将这些信息放在用户配置文件中:
- 用户可以看到但不需要修改这些"隐藏"配置
- 暴露了应用内部实现细节
- 用户可能误修改导致功能异常
## 讨论内容
### 配置文件分离
| 配置文件 | 用途 | 位置 | 内容 |
|---------|------|------|------|
| **用户配置** | 运行时用户数据 | `~/.config/pop/config.yml` | 账户、邮箱服务、默认行为 |
| **项目配置** | 应用开发相关 | `config/project.go` | 客户端信息、需要 ID 命令的 provider 集合 |
### 用户配置示例
```yaml
from:
account: work
defaults:
encryption: ssl
insecure: false
unsafe_html: false
accounts:
- name: work
email: foolsecret@163.com
provider: "163"
username: foolsecret@163.com
password: xxx
imap:
host: imap.163.com
port: 993
smtp:
host: smtp.163.com
port: 465
```
### 项目配置示例 (config/project.go)
```go
var ProjectConfig = struct {
Info Info
ProvidersNeedingCheckID map[string]bool
}{
Info: Info{
Name: "pop",
Version: "1.0",
Vendor: "charmbracelet",
},
ProvidersNeedingCheckID: map[string]bool{
"163": true,
"QQ": true,
},
}
```
### CheckID 覆盖机制
用户可以在账户级别覆盖 CheckID 行为:
```yaml
accounts:
- name: work
check_id: false # 禁用该账户的 ID 命令发送
```
逻辑优先级:
1. 用户明确设置 `check_id: false` → 不发送
2. 用户明确设置 `check_id: true` → 发送
3. 未设置 → 使用项目配置的 `ProvidersNeedingCheckID` 判断
### 扩展场景
未来可以扩展项目配置:
- 环境变量控制
- 调试模式开关
- 不同 provider 的特殊处理
## 结论
项目配置与用户配置分离是合理的架构设计:
- 职责分离:开发者配置 vs 用户配置
- 安全性:隐藏实现细节
- 可维护性:修改项目配置不影响用户数据
## 待处理
- [ ] 实现 config/project.go
- [ ] 修改 config.go 移除敏感字段
- [ ] 修改 imap.go 添加 ID 命令逻辑
- [ ] 更新文档