fe43b9bdce
- 将README从英文翻译为中文 - 添加详细的API参考文档,包括所有管理接口和枚举值说明 - 补充安装、快速开始、认证方式等使用指南 refactor(client): 优化客户端代码结构并添加详细注释 - 为所有API方法添加中文注释和使用说明 - 改进Client结构体和Option配置的设计 - 统一错误处理和响应结构的文档说明
591 lines
24 KiB
Go
591 lines
24 KiB
Go
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"`
|
||
}
|