Files
email-serverr-cli/types.go
T
shiran fe43b9bdce docs(README): 更新文档为中文并完善API参考
- 将README从英文翻译为中文
- 添加详细的API参考文档,包括所有管理接口和枚举值说明
- 补充安装、快速开始、认证方式等使用指南

refactor(client): 优化客户端代码结构并添加详细注释

- 为所有API方法添加中文注释和使用说明
- 改进Client结构体和Option配置的设计
- 统一错误处理和响应结构的文档说明
2026-04-18 15:54:19 +08:00

591 lines
24 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package emailcli
import "time"
// PaginationResult 是分页接口的统一返回结构。
//
// {
// "list": [...], // 当前页数据
// "total": 123, // 总记录数
// "page": 1,
// "page_size": 20
// }
type PaginationResult[T any] struct {
List []T `json:"list"`
Total int64 `json:"total"`
Page int `json:"page"`
PageSize int `json:"page_size"`
}
// PaginationQuery 是所有列表接口的分页参数基类,
// 业务 Query 结构体可通过嵌入来复用。
// - Page: 页码,从 1 开始;省略时后端默认 1
// - PageSize: 每页大小,省略时后端默认 20,最大 100
type PaginationQuery struct {
Page int `json:"page,omitempty"`
PageSize int `json:"page_size,omitempty"`
}
// GormModel 对应后端 gorm.Model。注意后端该部分没有自定义 json tag,
// 因此字段使用 PascalCase 序列化(与数据库模型保持一致)。
type GormModel struct {
ID uint `json:"ID"`
CreatedAt time.Time `json:"CreatedAt"`
UpdatedAt time.Time `json:"UpdatedAt"`
DeletedAt *time.Time `json:"DeletedAt"`
}
// ============================================================
// Account 邮件账号
// ============================================================
// Account 表示一个邮件发送账号。
// AppKey 用于发件认证;AppSecret 只在创建或重置时返回一次,
// 入库时以 bcrypt 保存,SDK 不会回传。
type Account struct {
GormModel
UserID int `json:"user_id"` // 关联主平台用户 ID
Name string `json:"name"` // 账号名称
AppKey string `json:"app_key"` // 发件公钥
Status int8 `json:"status"` // 账号状态: 0=禁用 1=启用
AuditMode int8 `json:"audit_mode"` // 审核模式: 0=免审核 1=自动 2=人工
RateLimit int `json:"rate_limit"` // 频率限制(封/分钟),0 表示不限
DefaultChannelID *uint `json:"default_channel_id"` // 默认发件通道 ID
AllowedChannels string `json:"allowed_channels"` // 允许的通道 ID 列表 JSON 字符串,如 "[1,2]";空串=不限
DefaultSignatureID *uint `json:"default_signature_id"` // 默认签名 ID
Remark string `json:"remark"` // 备注
}
// CreateAccountReq 是创建账号的请求体。
type CreateAccountReq struct {
UserID int `json:"user_id"` // 必填,关联用户 ID
Name string `json:"name"` // 必填,账号名称,≤100
AuditMode *int8 `json:"audit_mode,omitempty"` // 可选,默认 0 免审核
RateLimit *int `json:"rate_limit,omitempty"` // 可选,0=不限
DefaultChannelID *uint `json:"default_channel_id,omitempty"` // 可选,默认发件通道 ID
AllowedChannels string `json:"allowed_channels,omitempty"` // 可选,允许通道 ID 列表的 JSON 字符串
Remark string `json:"remark,omitempty"` // 可选,备注
}
// CreateAccountResp 是创建账号后的返回,AppSecret 仅此一次明文展示。
type CreateAccountResp struct {
ID uint `json:"id"`
AppKey string `json:"app_key"`
AppSecret string `json:"app_secret"` // 明文密钥,务必妥善保存
Name string `json:"name"`
}
// UpdateAccountReq 所有字段均为可选;只对传入字段做局部更新。
type UpdateAccountReq struct {
Name *string `json:"name,omitempty"`
Status *int8 `json:"status,omitempty"` // 0=禁用 1=启用
AuditMode *int8 `json:"audit_mode,omitempty"` // 0=免审核 1=自动 2=人工
RateLimit *int `json:"rate_limit,omitempty"` // 封/分钟,0=不限
DefaultChannelID *uint `json:"default_channel_id,omitempty"` // 默认发件通道 ID
AllowedChannels *string `json:"allowed_channels,omitempty"` // 允许通道 ID 列表 JSON
DefaultSignatureID *uint `json:"default_signature_id,omitempty"` // 默认签名 ID
Remark *string `json:"remark,omitempty"`
}
// AccountListQuery 是账号列表过滤参数。
type AccountListQuery struct {
PaginationQuery
UserID *int `json:"user_id,omitempty"` // 按用户过滤
Status *int8 `json:"status,omitempty"` // 0=禁用 1=启用
Keyword string `json:"keyword,omitempty"` // 模糊匹配 name / remark
}
// ResetSecretResp 是重置密钥后的返回。
type ResetSecretResp struct {
AppSecret string `json:"app_secret"` // 新生成的明文密钥
}
// ============================================================
// Signature 签名
// ============================================================
// Signature 表示一个邮件签名。
// EnglishName 会作为 From 地址的 local 部分组装发件人(签名@域名)。
type Signature struct {
GormModel
UserID int `json:"user_id"`
AccountID *uint `json:"account_id"` // 为空表示用户全局签名
Title string `json:"title"` // 中文抬头
EnglishName string `json:"english_name"` // 英文标识(用于拼 From 地址)
Content string `json:"content"` // HTML 签名正文
Applicant string `json:"applicant"` // 申请人
ApplicantInfo string `json:"applicant_info"` // 申请说明
Status int8 `json:"status"` // 0=待审核 1=已通过 2=已驳回
RejectReason string `json:"reject_reason"`
Auditor string `json:"auditor"`
AuditedAt *time.Time `json:"audited_at"`
}
// CreateSignatureReq 是创建签名的请求体。新建签名默认 Status=0(待审核)。
type CreateSignatureReq struct {
UserID int `json:"user_id"` // 必填
AccountID *uint `json:"account_id,omitempty"` // 可选,绑定账号
Title string `json:"title"` // 必填,中文抬头
EnglishName string `json:"english_name"` // 必填,英文标识
Content string `json:"content,omitempty"` // HTML 签名内容
Applicant string `json:"applicant,omitempty"` // 申请人
ApplicantInfo string `json:"applicant_info,omitempty"` // 申请说明
}
// UpdateSignatureReq 局部更新签名字段。
type UpdateSignatureReq struct {
Title *string `json:"title,omitempty"`
EnglishName *string `json:"english_name,omitempty"`
Content *string `json:"content,omitempty"`
Applicant *string `json:"applicant,omitempty"`
ApplicantInfo *string `json:"applicant_info,omitempty"`
}
// AuditSignatureReq 是审核签名的请求体。
type AuditSignatureReq struct {
Status int8 `json:"status"` // 1=通过 2=驳回
RejectReason string `json:"reject_reason,omitempty"` // 驳回时填写
}
// SignatureListQuery 是签名列表过滤参数。
type SignatureListQuery struct {
PaginationQuery
AccountID *uint `json:"account_id,omitempty"`
Status *int8 `json:"status,omitempty"` // 0=待审核 1=已通过 2=已驳回
UserID *int `json:"user_id,omitempty"`
Keyword string `json:"keyword,omitempty"` // 模糊匹配 title / english_name
}
// ============================================================
// Mail 发送邮件
// ============================================================
// SendMailReq 是 POST /api/v1/mail/send 的请求体。
//
// Channel 为空时,后端按以下顺序自动选择:
// 1. Account.DefaultChannelID 对应的已启用通道;
// 2. Account.AllowedChannels 列表中的首个已启用通道。
type SendMailReq struct {
To []string `json:"to"` // 必填,收件人列表(至少 1 个)
Cc []string `json:"cc,omitempty"` // 抄送
Bcc []string `json:"bcc,omitempty"` // 密送
Subject string `json:"subject"` // 必填,主题
Body string `json:"body"` // 必填,正文
ContentType string `json:"content_type,omitempty"` // text/plain 或 text/html,默认 text/html
Channel string `json:"channel,omitempty"` // 通道 code;留空走默认/允许通道
SignatureID *uint `json:"signature_id,omitempty"` // 指定签名 ID(优先级低于 title)
SignatureTitle string `json:"signature_title,omitempty"` // 按 title + user_id 查找已审核签名
Attachments []AttachmentItem `json:"attachments,omitempty"` // 附件
}
// AttachmentItem 附件项,Content 为 base64 编码字符串。
type AttachmentItem struct {
Filename string `json:"filename"` // 文件名(含扩展名)
Content string `json:"content"` // base64 编码的文件内容
}
// SendMailResp 是发送邮件的返回结果。
type SendMailResp struct {
MailLogID uint `json:"mail_log_id"` // 创建的邮件日志 ID
Status string `json:"status"` // queued / pending_audit / rejected
}
// ============================================================
// MailLog 邮件日志
// ============================================================
// MailLog 邮件日志记录。
// Status 枚举:0=待审核 1=排队中 2=发送中 3=成功 4=失败 5=放弃 6=驳回
type MailLog struct {
GormModel
UserID int `json:"user_id"`
AccountID uint `json:"account_id"`
QuotaID *uint `json:"quota_id"` // 扣减的配额记录 ID
ChannelID *uint `json:"channel_id"` // 使用的发件通道 ID
SenderAccountID *uint `json:"sender_account_id"` // 实际使用的发信账号 ID
SignatureID *uint `json:"signature_id"`
MessageID string `json:"message_id"` // SMTP 返回的 Message-ID
FromAddress string `json:"from_address"` // 实际 From 地址
ToAddresses string `json:"to_addresses"` // JSON 字符串数组
CcAddresses string `json:"cc_addresses"` // JSON 字符串数组
BccAddresses string `json:"bcc_addresses"` // JSON 字符串数组
Subject string `json:"subject"`
ContentType string `json:"content_type"`
HasAttachment bool `json:"has_attachment"`
SourceIP string `json:"source_ip"` // 请求来源 IP
SourceType string `json:"source_type"` // http / smtp
Status int8 `json:"status"`
RetryCount int `json:"retry_count"`
MaxRetry int `json:"max_retry"`
ErrorMessage string `json:"error_message"`
SentAt *time.Time `json:"sent_at"`
}
// MailLogListQuery 是邮件日志列表过滤参数。
type MailLogListQuery struct {
PaginationQuery
UserID *int `json:"user_id,omitempty"`
AccountID *uint `json:"account_id,omitempty"`
Status *int8 `json:"status,omitempty"` // 见 MailLog.Status 枚举
StartDate string `json:"start_date,omitempty"` // 格式 YYYY-MM-DD
EndDate string `json:"end_date,omitempty"` // 格式 YYYY-MM-DD
To string `json:"to,omitempty"` // 精确匹配收件人
Keyword string `json:"keyword,omitempty"` // 模糊匹配主题/收件人
}
// MailLogDetail 邮件日志详情,包含完整正文。
type MailLogDetail struct {
Log MailLog `json:"log"`
Body string `json:"body"` // 邮件正文
}
// MailStatItem 按状态分组的邮件计数,用于概览统计。
type MailStatItem struct {
Status int8 `json:"status"`
Count int64 `json:"count"`
}
// ============================================================
// Quota 配额
// ============================================================
// MailQuota 配额记录。
// - QuotaType=1 总量:Total 为生命周期内的总配额
// - QuotaType=2 周期:每个 CycleUnit 周期重置 Used
type MailQuota struct {
GormModel
UserID int `json:"user_id"`
AccountID uint `json:"account_id"`
QuotaType int8 `json:"quota_type"` // 1=总量 2=周期
Total int `json:"total"`
Used int `json:"used"`
ExpireAt *time.Time `json:"expire_at"` // 到期时间,仅总量配额有意义
CycleUnit string `json:"cycle_unit"` // day/week/month/year
CycleResetAt *time.Time `json:"cycle_reset_at"` // 周期起始时间
Status int8 `json:"status"` // 0=禁用 1=启用
}
// CreateQuotaReq 创建配额。
type CreateQuotaReq struct {
AccountID uint `json:"account_id"` // 必填
QuotaType int8 `json:"quota_type"` // 必填,1=总量 2=周期
Total int `json:"total"` // 必填,配额上限
ExpireAt string `json:"expire_at,omitempty"` // YYYY-MM-DD HH:mm:ss
CycleUnit string `json:"cycle_unit,omitempty"` // day/week/month/year
CycleResetAt string `json:"cycle_reset_at,omitempty"` // 周期起点
}
// UpdateQuotaReq 局部更新配额。
type UpdateQuotaReq struct {
Total *int `json:"total,omitempty"`
Status *int8 `json:"status,omitempty"`
ExpireAt *string `json:"expire_at,omitempty"`
CycleUnit *string `json:"cycle_unit,omitempty"`
CycleResetAt *string `json:"cycle_reset_at,omitempty"`
}
// QuotaListQuery 配额列表过滤参数。
type QuotaListQuery struct {
PaginationQuery
AccountID *uint `json:"account_id,omitempty"`
UserID *int `json:"user_id,omitempty"`
Status *int8 `json:"status,omitempty"`
}
// QuotaSummary 指定账号的配额汇总信息。
type QuotaSummary struct {
AccountID uint `json:"account_id"`
TotalQuota int `json:"total_quota"` // 所有配额累加总量
TotalUsed int `json:"total_used"` // 已用
TotalRemaining int `json:"total_remaining"` // 剩余
Details []MailQuota `json:"details"` // 每条配额明细
}
// ============================================================
// Channel 通道
// ============================================================
// Channel 发件通道,一个通道下可挂多个 SenderAccount,由 Strategy 决定分发逻辑。
type Channel struct {
GormModel
Name string `json:"name"`
Code string `json:"code"` // 唯一标识,发件请求中 channel 字段填这个
Description string `json:"description"`
Strategy string `json:"strategy"` // round_robin / weight / least_used
Status int8 `json:"status"` // 0=禁用 1=启用
}
// CreateChannelReq 创建通道。
type CreateChannelReq struct {
Name string `json:"name"` // 必填
Code string `json:"code"` // 必填,唯一
Description string `json:"description,omitempty"`
Strategy string `json:"strategy,omitempty"` // 默认 round_robin
}
// UpdateChannelReq 局部更新通道。
type UpdateChannelReq struct {
Name *string `json:"name,omitempty"`
Description *string `json:"description,omitempty"`
Strategy *string `json:"strategy,omitempty"`
Status *int8 `json:"status,omitempty"`
}
// ChannelListQuery 通道列表过滤参数。
type ChannelListQuery struct {
PaginationQuery
Status *int8 `json:"status,omitempty"`
Keyword string `json:"keyword,omitempty"` // 模糊匹配 name / code
}
// ============================================================
// SenderAccount 发信账号(SMTP
// ============================================================
// SenderAccount 挂在某个 Channel 下的 SMTP 发信账号。
type SenderAccount struct {
GormModel
ChannelID uint `json:"channel_id"`
Name string `json:"name"`
SmtpHost string `json:"smtp_host"`
SmtpPort int `json:"smtp_port"`
SmtpUser string `json:"smtp_user"`
SmtpSSL bool `json:"smtp_ssl"`
FromName string `json:"from_name"`
FromAddress string `json:"from_address"`
DailyLimit int `json:"daily_limit"` // 每日发送上限,0=不限
DailySent int `json:"daily_sent"` // 当日已发送数
Weight int `json:"weight"` // Strategy=weight 时使用
Status int8 `json:"status"` // 0=禁用 1=启用
LastCheckAt *time.Time `json:"last_check_at"`
LastCheckResult string `json:"last_check_result"`
}
// CreateSenderReq 创建发信账号。Password 只存密文,不会回显。
type CreateSenderReq struct {
Name string `json:"name"` // 必填
SmtpHost string `json:"smtp_host"` // 必填
SmtpPort int `json:"smtp_port"` // 必填
SmtpUser string `json:"smtp_user"` // 必填
SmtpPassword string `json:"smtp_password"` // 必填
SmtpSSL *bool `json:"smtp_ssl,omitempty"`
FromName string `json:"from_name,omitempty"`
FromAddress string `json:"from_address"` // 必填
DailyLimit *int `json:"daily_limit,omitempty"`
Weight *int `json:"weight,omitempty"`
}
// UpdateSenderReq 局部更新发信账号。
type UpdateSenderReq struct {
Name *string `json:"name,omitempty"`
SmtpHost *string `json:"smtp_host,omitempty"`
SmtpPort *int `json:"smtp_port,omitempty"`
SmtpUser *string `json:"smtp_user,omitempty"`
SmtpPassword *string `json:"smtp_password,omitempty"`
SmtpSSL *bool `json:"smtp_ssl,omitempty"`
FromName *string `json:"from_name,omitempty"`
FromAddress *string `json:"from_address,omitempty"`
DailyLimit *int `json:"daily_limit,omitempty"`
Weight *int `json:"weight,omitempty"`
Status *int8 `json:"status,omitempty"`
}
// SenderListQuery 发信账号列表过滤参数。
type SenderListQuery struct {
PaginationQuery
Status *int8 `json:"status,omitempty"`
Keyword string `json:"keyword,omitempty"`
}
// ============================================================
// Audit 审核
// ============================================================
// MailAudit 邮件审核记录。
type MailAudit struct {
GormModel
MailLogID uint `json:"mail_log_id"`
UserID int `json:"user_id"`
AccountID uint `json:"account_id"`
AuditType int8 `json:"audit_type"` // 1=自动 2=人工
Action int8 `json:"action"` // 1=通过 2=驳回
RejectReason string `json:"reject_reason"`
HitRules string `json:"hit_rules"` // 命中规则列表 JSON
Auditor string `json:"auditor"`
AuditedAt time.Time `json:"audited_at"`
}
// AuditPendingQuery 待审核列表过滤参数。
type AuditPendingQuery struct {
PaginationQuery
UserID *int `json:"user_id,omitempty"`
AccountID *uint `json:"account_id,omitempty"`
Keyword string `json:"keyword,omitempty"` // 模糊匹配主题/收件人
}
// AuditLogQuery 审核记录列表过滤参数。
type AuditLogQuery struct {
PaginationQuery
AuditType *int8 `json:"audit_type,omitempty"` // 1=自动 2=人工
Action *int8 `json:"action,omitempty"` // 1=通过 2=驳回
UserID *int `json:"user_id,omitempty"`
StartDate string `json:"start_date,omitempty"` // YYYY-MM-DD
EndDate string `json:"end_date,omitempty"` // YYYY-MM-DD
}
// AuditRejectReq 驳回审核请求体。
type AuditRejectReq struct {
RejectReason string `json:"reject_reason"` // 建议填写驳回原因
}
// BatchAuditApproveReq 批量通过请求体。
type BatchAuditApproveReq struct {
MailLogIDs []uint `json:"mail_log_ids"`
}
// BatchAuditRejectReq 批量驳回请求体。
type BatchAuditRejectReq struct {
MailLogIDs []uint `json:"mail_log_ids"`
RejectReason string `json:"reject_reason"`
}
// AuditStats 审核概览统计(用于仪表盘)。
type AuditStats struct {
PendingCount int64 `json:"pending_count"` // 待审核数量
TodayDetails []AuditDetailCount `json:"today_details"` // 今日按 type/action 分组
}
// AuditDetailCount 按 AuditType+Action 分组的计数。
type AuditDetailCount struct {
AuditType int8 `json:"audit_type"`
Action int8 `json:"action"`
Count int64 `json:"count"`
}
// ============================================================
// AuditRule 审核规则
// ============================================================
// AuditRule 审核规则。自动审核会按 Priority 从高到低依次评估,
// 命中即返回 Action。
type AuditRule struct {
GormModel
Name string `json:"name"`
RuleType string `json:"rule_type"` // keyword/regex/domain
Target string `json:"target"` // subject/body/to/from
Condition string `json:"condition"` // 关键词或正则
Action int8 `json:"action"` // 1=自动通过 2=自动驳回 3=转人工
Priority int `json:"priority"` // 数字越大优先级越高
Status int8 `json:"status"` // 0=禁用 1=启用
Remark string `json:"remark"`
}
// CreateAuditRuleReq 创建规则。
type CreateAuditRuleReq struct {
Name string `json:"name"` // 必填
RuleType string `json:"rule_type"` // 必填,keyword/regex/domain
Target string `json:"target"` // 必填,subject/body/to/from
Condition string `json:"condition"` // 必填
Action int8 `json:"action"` // 必填,1/2/3
Priority *int `json:"priority,omitempty"`
Remark string `json:"remark,omitempty"`
}
// UpdateAuditRuleReq 局部更新规则。
type UpdateAuditRuleReq struct {
Name *string `json:"name,omitempty"`
RuleType *string `json:"rule_type,omitempty"`
Target *string `json:"target,omitempty"`
Condition *string `json:"condition,omitempty"`
Action *int8 `json:"action,omitempty"`
Priority *int `json:"priority,omitempty"`
Status *int8 `json:"status,omitempty"`
Remark *string `json:"remark,omitempty"`
}
// TestAuditRuleReq 在不发送邮件的前提下测试规则命中情况。
type TestAuditRuleReq struct {
Subject string `json:"subject,omitempty"`
Body string `json:"body,omitempty"`
To []string `json:"to,omitempty"`
From string `json:"from,omitempty"`
AccountID uint `json:"account_id,omitempty"`
}
// TestAuditRuleResp 规则测试结果。
type TestAuditRuleResp struct {
Action string `json:"action"` // approve/reject/to_manual/none
HitRules []HitRuleEntry `json:"hit_rules"` // 命中的规则列表
}
// HitRuleEntry 命中规则信息。
type HitRuleEntry struct {
RuleID uint `json:"rule_id"`
RuleName string `json:"rule_name"`
RuleType string `json:"rule_type"`
}
// ============================================================
// Queue 发送队列
// ============================================================
// QueueStatusData 队列状态快照。
// - Queues: key = 通道 code, value = 该通道排队长度
// - DelayQueue: 延迟重试队列长度
type QueueStatusData struct {
Queues map[string]int `json:"queues"`
DelayQueue int `json:"delay_queue"`
}
// QueuePendingQuery 队列待发送邮件过滤参数。
type QueuePendingQuery struct {
PaginationQuery
ChannelID *uint `json:"channel_id,omitempty"`
UserID *int `json:"user_id,omitempty"`
AccountID *uint `json:"account_id,omitempty"`
}
// ============================================================
// Check 健康检查
// ============================================================
// CheckLog 发信账号健康检查记录。
// 通过向 verification 地址发测试邮件并等待 webhook 回调验证收信可用性。
type CheckLog struct {
ID uint `json:"id"`
SenderAccountID uint `json:"sender_account_id"`
VerificationCode string `json:"verification_code"`
SentAt time.Time `json:"sent_at"`
Received bool `json:"received"` // 是否收到回执
ReceivedAt *time.Time `json:"received_at"`
LatencyMs int `json:"latency_ms"` // 端到端延迟,毫秒
ErrorMessage string `json:"error_message"`
CreatedAt time.Time `json:"created_at"`
}
// CheckLogQuery 健康检查日志过滤参数。
type CheckLogQuery struct {
PaginationQuery
SenderAccountID *uint `json:"sender_account_id,omitempty"`
StartDate string `json:"start_date,omitempty"`
EndDate string `json:"end_date,omitempty"`
}
// SenderHealth 发信账号健康汇总。
type SenderHealth struct {
SenderAccountID uint `json:"sender_account_id"`
Name string `json:"name"`
FromAddress string `json:"from_address"`
Status int8 `json:"status"`
LastCheckResult string `json:"last_check_result"`
TotalChecks int64 `json:"total_checks"`
SuccessChecks int64 `json:"success_checks"`
}
// TriggerCheckResp 手动触发健康检查的返回。
type TriggerCheckResp struct {
Result string `json:"result"` // ok / failed
Error string `json:"error,omitempty"`
CheckLog *CheckLog `json:"check_log,omitempty"`
}