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

@@ -16,11 +16,14 @@
## 配置文件格式 ## 配置文件格式
```yaml ```yaml
from:
account: foolsecret@163.com
accounts: accounts:
- - name: work
email: 邮箱 email: 邮箱
provider: 163 provider: 163
username: 用户名 username: foolsecret@163.com
password: 密钥 password: 密钥
encryption: ssl encryption: ssl
insecure: false insecure: false
@@ -30,8 +33,17 @@ accounts:
smtp: smtp:
host: smtp.163.com host: smtp.163.com
port: 465 port: 465
- name: qqemail
-
email: 邮箱 email: 邮箱
provider: qq provider: qq
username: xxx@qq.com
password: QQ邮箱IMAP授权码
encryption: ssl
insecure: fales
imap:
host: imap.qq.com
port: 993
smtp:
host: smtp.qq.com
port: 465
``` ```

219
config.go
View File

@@ -11,22 +11,31 @@ import (
const configFileName = "config.yml" const configFileName = "config.yml"
type Config struct { type Config struct {
From string `yaml:"from"` From FromConfig `yaml:"from"`
Defaults DefaultsConfig `yaml:"defaults"`
Signature string `yaml:"signature"` Signature string `yaml:"signature"`
SMTP SMTPConfig `yaml:"smtp"`
UnsafeHTML bool `yaml:"unsafe_html"` UnsafeHTML bool `yaml:"unsafe_html"`
Accounts []Account `yaml:"accounts"` Accounts []Account `yaml:"accounts"`
} }
type FromConfig struct {
Account string `yaml:"account"`
}
type DefaultsConfig struct {
Encryption string `yaml:"encryption"`
Insecure bool `yaml:"insecure"`
}
type Account struct { type Account struct {
Name string `yaml:"name"` Name string `yaml:"name"`
Email string `yaml:"email"` Email string `yaml:"email"`
Provider string `yaml:"provider"` Provider string `yaml:"provider"`
Username string `yaml:"username"` Username string `yaml:"username"`
Password string `yaml:"password"` Password string `yaml:"password"`
CheckID *bool `yaml:"check_id"`
IMAP IMAPConfig `yaml:"imap"` IMAP IMAPConfig `yaml:"imap"`
SMTP SMTPConfig `yaml:"smtp"` SMTP SMTPConfig `yaml:"smtp"`
SMTPEncryption string `yaml:"smtp_encryption"`
} }
type IMAPConfig struct { type IMAPConfig struct {
@@ -48,42 +57,12 @@ type SMTPConfig struct {
} }
var defaultConfig = Config{ var defaultConfig = Config{
From: "", From: FromConfig{},
Defaults: DefaultsConfig{Encryption: "starttls"},
Signature: "", Signature: "",
SMTP: SMTPConfig{
Host: "",
Port: 587,
Username: "",
Password: "",
Encryption: "starttls",
InsecureSkipVerify: false,
},
UnsafeHTML: false, UnsafeHTML: false,
} }
var emailProviders = map[string]SMTPConfig{
"163": {
Host: "smtp.163.com",
Port: 465,
Encryption: "ssl",
},
"QQ": {
Host: "smtp.qq.com",
Port: 465,
Encryption: "ssl",
},
"Gmail": {
Host: "smtp.gmail.com",
Port: 465,
Encryption: "ssl",
},
"Outlook": {
Host: "smtp.office365.com",
Port: 587,
Encryption: "starttls",
},
}
var providerDefaults = map[string]struct { var providerDefaults = map[string]struct {
IMAPHost string IMAPHost string
IMAPPort int IMAPPort int
@@ -100,14 +79,6 @@ var providerDefaults = map[string]struct {
SMTPPort: 465, SMTPPort: 465,
SMTPEncryption: "ssl", SMTPEncryption: "ssl",
}, },
"188": {
IMAPHost: "imap.188.com",
IMAPPort: 993,
IMAPEncryption: "ssl",
SMTPHost: "smtp.188.com",
SMTPPort: 465,
SMTPEncryption: "ssl",
},
"QQ": { "QQ": {
IMAPHost: "imap.qq.com", IMAPHost: "imap.qq.com",
IMAPPort: 993, IMAPPort: 993,
@@ -116,22 +87,6 @@ var providerDefaults = map[string]struct {
SMTPPort: 465, SMTPPort: 465,
SMTPEncryption: "ssl", SMTPEncryption: "ssl",
}, },
"Gmail": {
IMAPHost: "imap.gmail.com",
IMAPPort: 993,
IMAPEncryption: "ssl",
SMTPHost: "smtp.gmail.com",
SMTPPort: 465,
SMTPEncryption: "ssl",
},
"Outlook": {
IMAPHost: "outlook.office365.com",
IMAPPort: 993,
IMAPEncryption: "ssl",
SMTPHost: "smtp.office365.com",
SMTPPort: 587,
SMTPEncryption: "starttls",
},
} }
var imapProviders = map[string]IMAPConfig{ var imapProviders = map[string]IMAPConfig{
@@ -147,43 +102,44 @@ var imapProviders = map[string]IMAPConfig{
Username: "", Username: "",
Password: "", Password: "",
}, },
"Gmail": {
Host: "imap.gmail.com",
Port: 993,
Username: "",
Password: "",
},
"Outlook": {
Host: "outlook.office365.com",
Port: 993,
Username: "",
Password: "",
},
} }
func normalizeAccount(acc Account) Account { func normalizeAccount(acc Account, defaults DefaultsConfig) Account {
if acc.Provider == "" { if acc.Provider == "" {
acc.Provider = getProviderName(acc.Email) acc.Provider = getProviderName(acc.Email)
} }
if defaults, ok := providerDefaults[acc.Provider]; ok { if providerDefaults, ok := providerDefaults[acc.Provider]; ok {
if acc.IMAP.Host == "" { if acc.IMAP.Host == "" {
acc.IMAP.Host = defaults.IMAPHost acc.IMAP.Host = providerDefaults.IMAPHost
acc.IMAP.Port = defaults.IMAPPort acc.IMAP.Port = providerDefaults.IMAPPort
} }
if acc.IMAP.Encryption == "" && defaults.IMAPEncryption != "" { if acc.IMAP.Encryption == "" && providerDefaults.IMAPEncryption != "" {
acc.IMAP.Encryption = defaults.IMAPEncryption acc.IMAP.Encryption = providerDefaults.IMAPEncryption
} }
if acc.SMTP.Host == "" { if acc.SMTP.Host == "" {
acc.SMTP.Host = defaults.SMTPHost acc.SMTP.Host = providerDefaults.SMTPHost
acc.SMTP.Port = defaults.SMTPPort acc.SMTP.Port = providerDefaults.SMTPPort
} }
if acc.SMTPEncryption == "" { if acc.SMTP.Encryption == "" && providerDefaults.SMTPEncryption != "" {
acc.SMTPEncryption = defaults.SMTPEncryption acc.SMTP.Encryption = providerDefaults.SMTPEncryption
} }
if acc.SMTP.Encryption == "" && acc.SMTPEncryption != "" {
acc.SMTP.Encryption = acc.SMTPEncryption
} }
if defaults.Encryption != "" {
if acc.IMAP.Encryption == "" {
acc.IMAP.Encryption = defaults.Encryption
}
if acc.SMTP.Encryption == "" {
acc.SMTP.Encryption = defaults.Encryption
}
}
if acc.IMAP.InsecureSkipVerify == false && defaults.Insecure {
acc.IMAP.InsecureSkipVerify = defaults.Insecure
}
if acc.SMTP.InsecureSkipVerify == false && defaults.Insecure {
acc.SMTP.InsecureSkipVerify = defaults.Insecure
} }
if acc.Username == "" { if acc.Username == "" {
@@ -206,6 +162,11 @@ func normalizeAccount(acc Account) Account {
acc.Name = acc.Provider acc.Name = acc.Provider
} }
if acc.CheckID == nil {
defaultCheckID := ProjectConfig.ProvidersNeedingCheckID[acc.Provider]
acc.CheckID = &defaultCheckID
}
return acc return acc
} }
@@ -301,26 +262,10 @@ func getAccounts() ([]Account, error) {
return nil, err return nil, err
} }
var accounts []Account accounts := cfg.Accounts
if cfg.SMTP.Username != "" {
accounts = append(accounts, Account{
Name: getProviderName(cfg.SMTP.Username),
Email: cfg.SMTP.Username,
SMTP: cfg.SMTP,
IMAP: IMAPConfig{
Host: getIMAPHost(cfg.SMTP.Username),
Port: 993,
Username: cfg.SMTP.Username,
Password: cfg.SMTP.Password,
},
})
}
accounts = append(accounts, cfg.Accounts...)
for i := range accounts { for i := range accounts {
accounts[i] = normalizeAccount(accounts[i]) accounts[i] = normalizeAccount(accounts[i], cfg.Defaults)
} }
return accounts, nil return accounts, nil
@@ -330,23 +275,10 @@ func getProviderName(email string) string {
if strings.HasSuffix(email, "@163.com") || strings.HasSuffix(email, "@vip.163.com") { if strings.HasSuffix(email, "@163.com") || strings.HasSuffix(email, "@vip.163.com") {
return "163" return "163"
} }
if strings.HasSuffix(email, "@188.com") || strings.HasSuffix(email, "@vip.188.com") {
return "188"
}
if strings.HasSuffix(email, "@qq.com") || strings.HasSuffix(email, "@vip.qq.com") { if strings.HasSuffix(email, "@qq.com") || strings.HasSuffix(email, "@vip.qq.com") {
return "QQ" return "QQ"
} }
if strings.HasSuffix(email, "@gmail.com") { return "custom"
return "Gmail"
}
if strings.HasSuffix(email, "@outlook.com") || strings.HasSuffix(email, "@office365.com") {
return "Outlook"
}
parts := strings.Split(email, "@")
if len(parts) > 1 {
return strings.Split(parts[1], ".")[0]
}
return "Email"
} }
func getIMAPHost(email string) string { func getIMAPHost(email string) string {
@@ -356,11 +288,60 @@ func getIMAPHost(email string) string {
if strings.HasSuffix(email, "@qq.com") { if strings.HasSuffix(email, "@qq.com") {
return "imap.qq.com" return "imap.qq.com"
} }
if strings.HasSuffix(email, "@gmail.com") { return ""
return "imap.gmail.com" }
func getDefaultFromEmail() string {
cfg, err := loadConfig()
if err != nil || cfg.From.Account == "" {
return ""
}
accounts, err := getAccounts()
if err != nil {
return ""
}
for _, acc := range accounts {
if acc.Name == cfg.From.Account {
if acc.Email != "" {
return acc.Email
}
return acc.Username
} }
if strings.HasSuffix(email, "@outlook.com") || strings.HasSuffix(email, "@office365.com") {
return "outlook.office365.com"
} }
return "" return ""
} }
func getDefaultAccount(accounts []Account, accountName string) *Account {
if accountName == "" {
return nil
}
for i := range accounts {
if accounts[i].Name == accountName {
return &accounts[i]
}
}
return nil
}
type Info struct {
Name string
Version string
Vendor string
}
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,
},
}

View File

@@ -10,20 +10,47 @@
## 讨论内容 ## 讨论内容
### 简化方案 ### 最终配置格式
用户建议采用简化配置:
```yaml ```yaml
from:
account: work # 通过 name 引用账户
defaults:
encryption: ssl
insecure: false
unsafe_html: false
signature: ""
accounts: accounts:
- name: "工作邮箱" - name: work
email: "user@163.com" email: foolsecret@163.com
provider: "163" # 自动填充 imap/smtp provider: 163
username: "user@163.com" # 统一认证 username: foolsecret@163.com
password: "xxx" password: xxx
smtp_encryption: "ssl" # 可选 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**: 通过邮箱后缀自动判断 1. **自动识别 Provider**: 通过邮箱后缀自动判断
@@ -33,35 +60,26 @@ accounts:
- `@outlook.com` / `@office365.com` → Outlook - `@outlook.com` / `@office365.com` → Outlook
- 其他 → custom - 其他 → 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 字段 | | 1 | config.go | 新增 FromConfig 和 DefaultsConfig 结构 |
| 2 | config.go | 添加 normalizeAccount() 自动填充默认值 | | 2 | config.go | 修改 normalizeAccount() 支持 defaults |
| 3 | config.go | 添加 providerDefaults 映射表 | | 3 | config.go | 新增 getDefaultFromEmail() 和 getDefaultAccount() |
| 4 | config.go | 修改 getAccounts() 调用 normalize | | 4 | main.go | 使用新函数获取默认账户信息 |
| 5 | onboarding.go | 修改交互流程,支持自动识别和默认值 | | 5 | 测试 | 验证配置读取和发送功能 |
## 待处理 ## 已完成
- [ ] 实现 config.go 修改 - [x] 实现 config.go 修改
- [ ] 实现 onboarding.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 命令逻辑
- [ ] 更新文档

14
imap.go
View File

@@ -62,6 +62,20 @@ func FetchUnreadEmails(account Account, days int) ([]ReceivedEmail, error) {
} }
defer m.Close() defer m.Close()
if account.CheckID != nil && *account.CheckID {
info := ProjectConfig.Info
idCmd := fmt.Sprintf("ID (\"name\" \"%s\" \"version\" \"%s\" \"vendor\" \"%s\")",
info.Name, info.Version, info.Vendor)
_, err := m.Exec(idCmd, false, 0, func(line []byte) error {
return nil
})
if err != nil {
fmt.Printf("WARNING: failed to send IMAP ID: %v\n", err)
}
m.Exec("NOOP", false, 0, nil)
}
err = m.SelectFolder("INBOX") err = m.SelectFolder("INBOX")
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to select inbox: %w", err) return nil, fmt.Errorf("failed to select inbox: %w", err)

63
main.go
View File

@@ -203,6 +203,7 @@ func init() {
rootCmd.AddCommand(ManCmd) rootCmd.AddCommand(ManCmd)
cfg, _ := loadConfig() cfg, _ := loadConfig()
_ = cfg
rootCmd.Flags().StringSliceVar(&bcc, "bcc", []string{}, "BCC recipients") rootCmd.Flags().StringSliceVar(&bcc, "bcc", []string{}, "BCC recipients")
rootCmd.Flags().StringSliceVar(&cc, "cc", []string{}, "CC recipients") rootCmd.Flags().StringSliceVar(&cc, "cc", []string{}, "CC recipients")
@@ -211,7 +212,7 @@ func init() {
rootCmd.Flags().StringVarP(&body, "body", "b", "", "Email's contents") rootCmd.Flags().StringVarP(&body, "body", "b", "", "Email's contents")
envFrom := os.Getenv(PopFrom) envFrom := os.Getenv(PopFrom)
if envFrom == "" { if envFrom == "" {
envFrom = cfg.From envFrom = getDefaultFromEmail()
} }
from = envFrom from = envFrom
rootCmd.Flags().StringVarP(&from, "from", "f", envFrom, "Email's sender"+commentStyle.Render("($"+PopFrom+")")) rootCmd.Flags().StringVarP(&from, "from", "f", envFrom, "Email's sender"+commentStyle.Render("($"+PopFrom+")"))
@@ -228,46 +229,52 @@ func init() {
} }
rootCmd.Flags().StringVarP(&signature, "signature", "x", envSignature, "Signature to display at the end of the email."+commentStyle.Render("($"+PopSignature+")")) rootCmd.Flags().StringVarP(&signature, "signature", "x", envSignature, "Signature to display at the end of the email."+commentStyle.Render("($"+PopSignature+")"))
envSMTPHost := os.Getenv(PopSMTPHost) envSMTPHost := os.Getenv(PopSMTPHost)
if envSMTPHost == "" {
envSMTPHost = cfg.SMTP.Host
}
smtpHost = envSMTPHost
rootCmd.Flags().StringVarP(&smtpHost, "smtp.host", "H", envSMTPHost, "Host of the SMTP server"+commentStyle.Render("($"+PopSMTPHost+")"))
envSMTPPort, _ := strconv.Atoi(os.Getenv(PopSMTPPort)) envSMTPPort, _ := strconv.Atoi(os.Getenv(PopSMTPPort))
if envSMTPPort == 0 { envSMTPUsername := os.Getenv(PopSMTPUsername)
envSMTPPort = cfg.SMTP.Port envSMTPPassword := os.Getenv(PopSMTPPassword)
envSMTPEncryption := os.Getenv(PopSMTPEncryption)
envInsecureSkipVerify := os.Getenv(PopSMTPInsecureSkipVerify) == "true"
defaultAccounts, _ := getAccounts()
defaultAccount := getDefaultAccount(defaultAccounts, cfg.From.Account)
if envSMTPHost == "" && defaultAccount != nil {
envSMTPHost = defaultAccount.SMTP.Host
}
if envSMTPPort == 0 && defaultAccount != nil {
envSMTPPort = defaultAccount.SMTP.Port
if envSMTPPort == 0 { if envSMTPPort == 0 {
envSMTPPort = 587 envSMTPPort = 587
} }
} }
smtpPort = envSMTPPort if envSMTPUsername == "" && defaultAccount != nil {
rootCmd.Flags().IntVarP(&smtpPort, "smtp.port", "P", envSMTPPort, "Port of the SMTP server"+commentStyle.Render("($"+PopSMTPPort+")")) envSMTPUsername = defaultAccount.SMTP.Username
envSMTPUsername := os.Getenv(PopSMTPUsername)
if envSMTPUsername == "" {
envSMTPUsername = cfg.SMTP.Username
} }
smtpUsername = envSMTPUsername if envSMTPPassword == "" && defaultAccount != nil {
rootCmd.Flags().StringVarP(&smtpUsername, "smtp.username", "U", envSMTPUsername, "Username of the SMTP server"+commentStyle.Render("($"+PopSMTPUsername+")")) envSMTPPassword = defaultAccount.SMTP.Password
envSMTPPassword := os.Getenv(PopSMTPPassword)
if envSMTPPassword == "" {
envSMTPPassword = cfg.SMTP.Password
} }
smtpPassword = envSMTPPassword if envSMTPEncryption == "" && defaultAccount != nil {
rootCmd.Flags().StringVarP(&smtpPassword, "smtp.password", "p", envSMTPPassword, "Password of the SMTP server"+commentStyle.Render("($"+PopSMTPPassword+")")) envSMTPEncryption = defaultAccount.SMTP.Encryption
envSMTPEncryption := os.Getenv(PopSMTPEncryption)
if envSMTPEncryption == "" {
envSMTPEncryption = cfg.SMTP.Encryption
if envSMTPEncryption == "" { if envSMTPEncryption == "" {
envSMTPEncryption = "starttls" envSMTPEncryption = "starttls"
} }
} }
smtpEncryption = envSMTPEncryption if !envInsecureSkipVerify && defaultAccount != nil {
rootCmd.Flags().StringVarP(&smtpEncryption, "smtp.encryption", "e", envSMTPEncryption, "Encryption type of the SMTP server (starttls, ssl, or none)"+commentStyle.Render("($"+PopSMTPEncryption+")")) envInsecureSkipVerify = defaultAccount.SMTP.InsecureSkipVerify
envInsecureSkipVerify := os.Getenv(PopSMTPInsecureSkipVerify) == "true"
if !envInsecureSkipVerify {
envInsecureSkipVerify = cfg.SMTP.InsecureSkipVerify
} }
smtpHost = envSMTPHost
smtpPort = envSMTPPort
smtpUsername = envSMTPUsername
smtpPassword = envSMTPPassword
smtpEncryption = envSMTPEncryption
smtpInsecureSkipVerify = envInsecureSkipVerify smtpInsecureSkipVerify = envInsecureSkipVerify
rootCmd.Flags().StringVarP(&smtpHost, "smtp.host", "H", envSMTPHost, "Host of the SMTP server"+commentStyle.Render("($"+PopSMTPHost+")"))
rootCmd.Flags().IntVarP(&smtpPort, "smtp.port", "P", envSMTPPort, "Port of the SMTP server"+commentStyle.Render("($"+PopSMTPPort+")"))
rootCmd.Flags().StringVarP(&smtpUsername, "smtp.username", "U", envSMTPUsername, "Username of the SMTP server"+commentStyle.Render("($"+PopSMTPUsername+")"))
rootCmd.Flags().StringVarP(&smtpPassword, "smtp.password", "p", envSMTPPassword, "Password of the SMTP server"+commentStyle.Render("($"+PopSMTPPassword+")"))
rootCmd.Flags().StringVarP(&smtpEncryption, "smtp.encryption", "e", envSMTPEncryption, "Encryption type of the SMTP server (starttls, ssl, or none)"+commentStyle.Render("($"+PopSMTPEncryption+")"))
rootCmd.Flags().BoolVarP(&smtpInsecureSkipVerify, "smtp.insecure", "i", envInsecureSkipVerify, "Skip TLS verification with SMTP server"+commentStyle.Render("($"+PopSMTPInsecureSkipVerify+")")) rootCmd.Flags().BoolVarP(&smtpInsecureSkipVerify, "smtp.insecure", "i", envInsecureSkipVerify, "Skip TLS verification with SMTP server"+commentStyle.Render("($"+PopSMTPInsecureSkipVerify+")"))
envResendAPIKey := os.Getenv(ResendAPIKey) envResendAPIKey := os.Getenv(ResendAPIKey)
rootCmd.Flags().StringVarP(&resendAPIKey, "resend.key", "r", envResendAPIKey, "API key for the Resend.com"+commentStyle.Render("($"+ResendAPIKey+")")) rootCmd.Flags().StringVarP(&resendAPIKey, "resend.key", "r", envResendAPIKey, "API key for the Resend.com"+commentStyle.Render("($"+ResendAPIKey+")"))

View File

@@ -156,9 +156,10 @@ func runOnboarding() error {
} }
cfg := Config{ cfg := Config{
From: email, From: FromConfig{Account: accountName},
Signature: "", Signature: "",
UnsafeHTML: unsafeHTML, UnsafeHTML: unsafeHTML,
Defaults: DefaultsConfig{Encryption: smtpEncryption},
Accounts: []Account{ Accounts: []Account{
{ {
Name: accountName, Name: accountName,
@@ -166,7 +167,6 @@ func runOnboarding() error {
Provider: provider, Provider: provider,
Username: smtpUsername, Username: smtpUsername,
Password: smtpPassword, Password: smtpPassword,
SMTPEncryption: smtpEncryption,
IMAP: IMAPConfig{ IMAP: IMAPConfig{
Host: imapHost, Host: imapHost,
Password: smtpPassword, Password: smtpPassword,