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:
20
AGENTS.md
20
AGENTS.md
@@ -16,11 +16,14 @@
|
||||
## 配置文件格式
|
||||
|
||||
```yaml
|
||||
from:
|
||||
account: foolsecret@163.com
|
||||
|
||||
accounts:
|
||||
-
|
||||
- name: work
|
||||
email: 邮箱
|
||||
provider: 163
|
||||
username: 用户名
|
||||
username: foolsecret@163.com
|
||||
password: 密钥
|
||||
encryption: ssl
|
||||
insecure: false
|
||||
@@ -30,8 +33,17 @@ accounts:
|
||||
smtp:
|
||||
host: smtp.163.com
|
||||
port: 465
|
||||
|
||||
-
|
||||
- name: qqemail
|
||||
email: 邮箱
|
||||
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
|
||||
```
|
||||
|
||||
241
config.go
241
config.go
@@ -11,22 +11,31 @@ import (
|
||||
const configFileName = "config.yml"
|
||||
|
||||
type Config struct {
|
||||
From string `yaml:"from"`
|
||||
Signature string `yaml:"signature"`
|
||||
SMTP SMTPConfig `yaml:"smtp"`
|
||||
UnsafeHTML bool `yaml:"unsafe_html"`
|
||||
Accounts []Account `yaml:"accounts"`
|
||||
From FromConfig `yaml:"from"`
|
||||
Defaults DefaultsConfig `yaml:"defaults"`
|
||||
Signature string `yaml:"signature"`
|
||||
UnsafeHTML bool `yaml:"unsafe_html"`
|
||||
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 {
|
||||
Name string `yaml:"name"`
|
||||
Email string `yaml:"email"`
|
||||
Provider string `yaml:"provider"`
|
||||
Username string `yaml:"username"`
|
||||
Password string `yaml:"password"`
|
||||
IMAP IMAPConfig `yaml:"imap"`
|
||||
SMTP SMTPConfig `yaml:"smtp"`
|
||||
SMTPEncryption string `yaml:"smtp_encryption"`
|
||||
Name string `yaml:"name"`
|
||||
Email string `yaml:"email"`
|
||||
Provider string `yaml:"provider"`
|
||||
Username string `yaml:"username"`
|
||||
Password string `yaml:"password"`
|
||||
CheckID *bool `yaml:"check_id"`
|
||||
IMAP IMAPConfig `yaml:"imap"`
|
||||
SMTP SMTPConfig `yaml:"smtp"`
|
||||
}
|
||||
|
||||
type IMAPConfig struct {
|
||||
@@ -48,42 +57,12 @@ type SMTPConfig struct {
|
||||
}
|
||||
|
||||
var defaultConfig = Config{
|
||||
From: "",
|
||||
Signature: "",
|
||||
SMTP: SMTPConfig{
|
||||
Host: "",
|
||||
Port: 587,
|
||||
Username: "",
|
||||
Password: "",
|
||||
Encryption: "starttls",
|
||||
InsecureSkipVerify: false,
|
||||
},
|
||||
From: FromConfig{},
|
||||
Defaults: DefaultsConfig{Encryption: "starttls"},
|
||||
Signature: "",
|
||||
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 {
|
||||
IMAPHost string
|
||||
IMAPPort int
|
||||
@@ -100,14 +79,6 @@ var providerDefaults = map[string]struct {
|
||||
SMTPPort: 465,
|
||||
SMTPEncryption: "ssl",
|
||||
},
|
||||
"188": {
|
||||
IMAPHost: "imap.188.com",
|
||||
IMAPPort: 993,
|
||||
IMAPEncryption: "ssl",
|
||||
SMTPHost: "smtp.188.com",
|
||||
SMTPPort: 465,
|
||||
SMTPEncryption: "ssl",
|
||||
},
|
||||
"QQ": {
|
||||
IMAPHost: "imap.qq.com",
|
||||
IMAPPort: 993,
|
||||
@@ -116,22 +87,6 @@ var providerDefaults = map[string]struct {
|
||||
SMTPPort: 465,
|
||||
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{
|
||||
@@ -147,43 +102,44 @@ var imapProviders = map[string]IMAPConfig{
|
||||
Username: "",
|
||||
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 == "" {
|
||||
acc.Provider = getProviderName(acc.Email)
|
||||
}
|
||||
|
||||
if defaults, ok := providerDefaults[acc.Provider]; ok {
|
||||
if providerDefaults, ok := providerDefaults[acc.Provider]; ok {
|
||||
if acc.IMAP.Host == "" {
|
||||
acc.IMAP.Host = defaults.IMAPHost
|
||||
acc.IMAP.Port = defaults.IMAPPort
|
||||
acc.IMAP.Host = providerDefaults.IMAPHost
|
||||
acc.IMAP.Port = providerDefaults.IMAPPort
|
||||
}
|
||||
if acc.IMAP.Encryption == "" && defaults.IMAPEncryption != "" {
|
||||
acc.IMAP.Encryption = defaults.IMAPEncryption
|
||||
if acc.IMAP.Encryption == "" && providerDefaults.IMAPEncryption != "" {
|
||||
acc.IMAP.Encryption = providerDefaults.IMAPEncryption
|
||||
}
|
||||
if acc.SMTP.Host == "" {
|
||||
acc.SMTP.Host = defaults.SMTPHost
|
||||
acc.SMTP.Port = defaults.SMTPPort
|
||||
acc.SMTP.Host = providerDefaults.SMTPHost
|
||||
acc.SMTP.Port = providerDefaults.SMTPPort
|
||||
}
|
||||
if acc.SMTPEncryption == "" {
|
||||
acc.SMTPEncryption = defaults.SMTPEncryption
|
||||
if acc.SMTP.Encryption == "" && providerDefaults.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 == "" {
|
||||
@@ -206,6 +162,11 @@ func normalizeAccount(acc Account) Account {
|
||||
acc.Name = acc.Provider
|
||||
}
|
||||
|
||||
if acc.CheckID == nil {
|
||||
defaultCheckID := ProjectConfig.ProvidersNeedingCheckID[acc.Provider]
|
||||
acc.CheckID = &defaultCheckID
|
||||
}
|
||||
|
||||
return acc
|
||||
}
|
||||
|
||||
@@ -301,26 +262,10 @@ func getAccounts() ([]Account, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var accounts []Account
|
||||
|
||||
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...)
|
||||
accounts := cfg.Accounts
|
||||
|
||||
for i := range accounts {
|
||||
accounts[i] = normalizeAccount(accounts[i])
|
||||
accounts[i] = normalizeAccount(accounts[i], cfg.Defaults)
|
||||
}
|
||||
|
||||
return accounts, nil
|
||||
@@ -330,23 +275,10 @@ func getProviderName(email string) string {
|
||||
if strings.HasSuffix(email, "@163.com") || strings.HasSuffix(email, "@vip.163.com") {
|
||||
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") {
|
||||
return "QQ"
|
||||
}
|
||||
if strings.HasSuffix(email, "@gmail.com") {
|
||||
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"
|
||||
return "custom"
|
||||
}
|
||||
|
||||
func getIMAPHost(email string) string {
|
||||
@@ -356,11 +288,60 @@ func getIMAPHost(email string) string {
|
||||
if strings.HasSuffix(email, "@qq.com") {
|
||||
return "imap.qq.com"
|
||||
}
|
||||
if strings.HasSuffix(email, "@gmail.com") {
|
||||
return "imap.gmail.com"
|
||||
return ""
|
||||
}
|
||||
|
||||
func getDefaultFromEmail() string {
|
||||
cfg, err := loadConfig()
|
||||
if err != nil || cfg.From.Account == "" {
|
||||
return ""
|
||||
}
|
||||
if strings.HasSuffix(email, "@outlook.com") || strings.HasSuffix(email, "@office365.com") {
|
||||
return "outlook.office365.com"
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
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,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -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 逻辑调整
|
||||
- [ ] 测试配置读取和写入
|
||||
102
doc/003-config-separation.md
Normal file
102
doc/003-config-separation.md
Normal 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
14
imap.go
@@ -62,6 +62,20 @@ func FetchUnreadEmails(account Account, days int) ([]ReceivedEmail, error) {
|
||||
}
|
||||
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")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to select inbox: %w", err)
|
||||
|
||||
63
main.go
63
main.go
@@ -203,6 +203,7 @@ func init() {
|
||||
rootCmd.AddCommand(ManCmd)
|
||||
|
||||
cfg, _ := loadConfig()
|
||||
_ = cfg
|
||||
|
||||
rootCmd.Flags().StringSliceVar(&bcc, "bcc", []string{}, "BCC recipients")
|
||||
rootCmd.Flags().StringSliceVar(&cc, "cc", []string{}, "CC recipients")
|
||||
@@ -211,7 +212,7 @@ func init() {
|
||||
rootCmd.Flags().StringVarP(&body, "body", "b", "", "Email's contents")
|
||||
envFrom := os.Getenv(PopFrom)
|
||||
if envFrom == "" {
|
||||
envFrom = cfg.From
|
||||
envFrom = getDefaultFromEmail()
|
||||
}
|
||||
from = envFrom
|
||||
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+")"))
|
||||
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))
|
||||
if envSMTPPort == 0 {
|
||||
envSMTPPort = cfg.SMTP.Port
|
||||
envSMTPUsername := os.Getenv(PopSMTPUsername)
|
||||
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 {
|
||||
envSMTPPort = 587
|
||||
}
|
||||
}
|
||||
smtpPort = envSMTPPort
|
||||
rootCmd.Flags().IntVarP(&smtpPort, "smtp.port", "P", envSMTPPort, "Port of the SMTP server"+commentStyle.Render("($"+PopSMTPPort+")"))
|
||||
envSMTPUsername := os.Getenv(PopSMTPUsername)
|
||||
if envSMTPUsername == "" {
|
||||
envSMTPUsername = cfg.SMTP.Username
|
||||
if envSMTPUsername == "" && defaultAccount != nil {
|
||||
envSMTPUsername = defaultAccount.SMTP.Username
|
||||
}
|
||||
smtpUsername = envSMTPUsername
|
||||
rootCmd.Flags().StringVarP(&smtpUsername, "smtp.username", "U", envSMTPUsername, "Username of the SMTP server"+commentStyle.Render("($"+PopSMTPUsername+")"))
|
||||
envSMTPPassword := os.Getenv(PopSMTPPassword)
|
||||
if envSMTPPassword == "" {
|
||||
envSMTPPassword = cfg.SMTP.Password
|
||||
if envSMTPPassword == "" && defaultAccount != nil {
|
||||
envSMTPPassword = defaultAccount.SMTP.Password
|
||||
}
|
||||
smtpPassword = envSMTPPassword
|
||||
rootCmd.Flags().StringVarP(&smtpPassword, "smtp.password", "p", envSMTPPassword, "Password of the SMTP server"+commentStyle.Render("($"+PopSMTPPassword+")"))
|
||||
envSMTPEncryption := os.Getenv(PopSMTPEncryption)
|
||||
if envSMTPEncryption == "" {
|
||||
envSMTPEncryption = cfg.SMTP.Encryption
|
||||
if envSMTPEncryption == "" && defaultAccount != nil {
|
||||
envSMTPEncryption = defaultAccount.SMTP.Encryption
|
||||
if envSMTPEncryption == "" {
|
||||
envSMTPEncryption = "starttls"
|
||||
}
|
||||
}
|
||||
smtpEncryption = envSMTPEncryption
|
||||
rootCmd.Flags().StringVarP(&smtpEncryption, "smtp.encryption", "e", envSMTPEncryption, "Encryption type of the SMTP server (starttls, ssl, or none)"+commentStyle.Render("($"+PopSMTPEncryption+")"))
|
||||
envInsecureSkipVerify := os.Getenv(PopSMTPInsecureSkipVerify) == "true"
|
||||
if !envInsecureSkipVerify {
|
||||
envInsecureSkipVerify = cfg.SMTP.InsecureSkipVerify
|
||||
if !envInsecureSkipVerify && defaultAccount != nil {
|
||||
envInsecureSkipVerify = defaultAccount.SMTP.InsecureSkipVerify
|
||||
}
|
||||
|
||||
smtpHost = envSMTPHost
|
||||
smtpPort = envSMTPPort
|
||||
smtpUsername = envSMTPUsername
|
||||
smtpPassword = envSMTPPassword
|
||||
smtpEncryption = envSMTPEncryption
|
||||
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+")"))
|
||||
envResendAPIKey := os.Getenv(ResendAPIKey)
|
||||
rootCmd.Flags().StringVarP(&resendAPIKey, "resend.key", "r", envResendAPIKey, "API key for the Resend.com"+commentStyle.Render("($"+ResendAPIKey+")"))
|
||||
|
||||
@@ -156,17 +156,17 @@ func runOnboarding() error {
|
||||
}
|
||||
|
||||
cfg := Config{
|
||||
From: email,
|
||||
From: FromConfig{Account: accountName},
|
||||
Signature: "",
|
||||
UnsafeHTML: unsafeHTML,
|
||||
Defaults: DefaultsConfig{Encryption: smtpEncryption},
|
||||
Accounts: []Account{
|
||||
{
|
||||
Name: accountName,
|
||||
Email: email,
|
||||
Provider: provider,
|
||||
Username: smtpUsername,
|
||||
Password: smtpPassword,
|
||||
SMTPEncryption: smtpEncryption,
|
||||
Name: accountName,
|
||||
Email: email,
|
||||
Provider: provider,
|
||||
Username: smtpUsername,
|
||||
Password: smtpPassword,
|
||||
IMAP: IMAPConfig{
|
||||
Host: imapHost,
|
||||
Password: smtpPassword,
|
||||
|
||||
Reference in New Issue
Block a user