- 将README从英文翻译为中文 - 添加详细的API参考文档,包括所有管理接口和枚举值说明 - 补充安装、快速开始、认证方式等使用指南 refactor(client): 优化客户端代码结构并添加详细注释 - 为所有API方法添加中文注释和使用说明 - 改进Client结构体和Option配置的设计 - 统一错误处理和响应结构的文档说明
15 KiB
email-serverr-cli
Email Server API 的 Go 客户端库。提供管理端(ServiceAuth)与发件端(AppAuth)两种客户端, 覆盖邮件发送、账号、签名、配额、通道/发信、审核、队列、健康检查等全部后端能力。
- 模块路径:
gitea.s1f.ren/shiran/email-serverr-cli - 依赖: 仅使用标准库
net/http、encoding/json,无第三方依赖 - 风格: 对每一类资源一个文件,请求/响应类型在
types.go,底层请求在client.go
安装
go get gitea.s1f.ren/shiran/email-serverr-cli
import emailcli "gitea.s1f.ren/shiran/email-serverr-cli"
快速开始
管理客户端(ServiceAuth)
client := emailcli.NewServiceClient(
"https://your-server.com",
"your-service-token",
)
accounts, err := client.ListAccounts(context.Background(), emailcli.AccountListQuery{
PaginationQuery: emailcli.PaginationQuery{Page: 1, PageSize: 20},
})
发件客户端(AppAuth)
client := emailcli.NewAppClient(
"https://your-server.com",
"your-app-key",
"your-app-secret",
)
resp, err := client.SendMail(context.Background(), emailcli.SendMailReq{
To: []string{"recipient@example.com"},
Subject: "Hello",
Body: "<h1>Hello World</h1>",
// Channel 可选:不传时优先使用账号默认通道,其次使用允许通道列表首个可用项
})
客户端选项
client := emailcli.NewServiceClient(baseURL, token,
emailcli.WithTimeout(60*time.Second),
emailcli.WithHTTPClient(customClient),
)
认证方式
| 模式 | 构造函数 | 请求头 | 适用范围 |
|---|---|---|---|
| ServiceAuth | NewServiceClient |
Authorization: Bearer <token> |
所有 /api/v1 管理接口 |
| AppAuth | NewAppClient |
X-App-Key + X-App-Secret |
仅 POST /api/v1/mail/send |
枚举值说明
Account.Status(账号状态)
| 值 | 含义 |
|---|---|
| 0 | 禁用 |
| 1 | 启用 |
Account.AuditMode(审核模式)
| 值 | 含义 |
|---|---|
| 0 | 免审核(直接入队) |
| 1 | 自动(按规则判定) |
| 2 | 人工(待审核) |
Signature.Status(签名状态)
| 值 | 含义 |
|---|---|
| 0 | 待审核 |
| 1 | 已通过 |
| 2 | 已驳回 |
MailLog.Status(邮件状态)
| 值 | 含义 |
|---|---|
| 0 | 待审核 |
| 1 | 排队中 |
| 2 | 发送中 |
| 3 | 成功 |
| 4 | 失败 |
| 5 | 放弃 |
| 6 | 驳回 |
MailQuota.QuotaType(配额类型)
| 值 | 含义 |
|---|---|
| 1 | 总量配额(total 为总发送上限) |
| 2 | 周期配额(到期自动重置) |
MailQuota.CycleUnit(配额周期单位)
当 quota_type=2 时生效,取值:day、week、month、year
MailQuota.Status
| 值 | 含义 |
|---|---|
| 0 | 禁用 |
| 1 | 启用 |
Channel.Status / SenderAccount.Status
| 值 | 含义 |
|---|---|
| 0 | 禁用 |
| 1 | 启用 |
Channel.Strategy(发信挑选策略)
| 值 | 含义 |
|---|---|
round_robin |
轮询(默认) |
weight |
按 weight 加权随机 |
least_used |
今日发送数最少优先 |
AuditRule.Action(规则动作)
| 值 | 含义 |
|---|---|
| 1 | 自动通过 |
| 2 | 自动驳回 |
| 3 | 转人工 |
AuditRule.RuleType / Target(规则类型与目标)
RuleType取值:keyword、regex、domainTarget取值:subject、body、to、from
MailAudit.AuditType(审核来源)
| 值 | 含义 |
|---|---|
| 1 | 自动 |
| 2 | 人工 |
MailAudit.Action(审核动作)
| 值 | 含义 |
|---|---|
| 1 | 通过 |
| 2 | 驳回 |
SendMailReq.ContentType
取值:text/plain(默认)、text/html
API 参考
所有管理接口挂载在 /api/v1 下。以下按功能模块分组,并给出方法签名、HTTP 路径与关键参数说明。
一、发送邮件(AppAuth)
SendMail(ctx, req SendMailReq) -> *SendMailResp
POST /api/v1/mail/send
SendMailReq 字段:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
To |
[]string |
是 | 收件人列表,至少 1 个 |
Cc |
[]string |
否 | 抄送 |
Bcc |
[]string |
否 | 密送 |
Subject |
string |
是 | 主题 |
Body |
string |
是 | 正文 |
ContentType |
string |
否 | 默认 text/html |
Channel |
string |
否 | 通道 code。为空时按 账号默认通道 → 账号允许通道首个可用 顺序自动解析 |
SignatureID |
*uint |
否 | 指定签名 ID(用户必须拥有且已审核) |
SignatureTitle |
string |
否 | 按 title + user_id 选择签名;未传则使用默认签名 |
Attachments |
[]AttachmentItem |
否 | 附件(filename + base64 content) |
SendMailResp 字段:
| 字段 | 类型 | 说明 |
|---|---|---|
MailLogID |
uint |
创建的邮件日志 ID |
Status |
string |
queued / pending_audit / rejected |
二、账号管理(ServiceAuth)
CreateAccount(ctx, req CreateAccountReq) -> *CreateAccountResp
POST /api/v1/accounts
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
UserID |
int |
是 | 关联用户 ID |
Name |
string |
是 | 账号名称(≤100) |
AuditMode |
*int8 |
否 | 审核模式枚举,默认 0 |
RateLimit |
*int |
否 | 频率限制(封/分钟),0 表示不限 |
DefaultChannelID |
*uint |
否 | 默认发件通道 ID |
AllowedChannels |
string |
否 | 允许发件通道 ID 列表的 JSON 字符串,例如 "[1,2]"。为空时视作不限制 |
Remark |
string |
否 | 备注 |
返回 CreateAccountResp(首次创建返回明文 AppSecret):
{ "id": 1, "app_key": "...", "app_secret": "只在此次展示", "name": "..." }
ListAccounts(ctx, q AccountListQuery) -> *PaginationResult[Account]
GET /api/v1/accounts?page=&page_size=&user_id=&status=&keyword=
| 参数 | 类型 | 说明 |
|---|---|---|
Page/PageSize |
int |
分页,PageSize 默认 20 |
UserID |
*int |
按用户筛选 |
Status |
*int8 |
账号状态(0/1) |
Keyword |
string |
模糊匹配 name 或 remark |
GetAccount(ctx, id uint) -> *Account
GET /api/v1/accounts/{id}
UpdateAccount(ctx, id uint, req UpdateAccountReq) -> *Account
PUT /api/v1/accounts/{id}
所有字段均为可选指针,只更新已传字段。
| 字段 | 类型 | 说明 |
|---|---|---|
Name |
*string |
|
Status |
*int8 |
启用/禁用 |
AuditMode |
*int8 |
|
RateLimit |
*int |
|
DefaultChannelID |
*uint |
默认发件通道 |
AllowedChannels |
*string |
允许发件通道 ID 列表 JSON |
DefaultSignatureID |
*uint |
默认签名 ID |
Remark |
*string |
DeleteAccount(ctx, id uint) error
DELETE /api/v1/accounts/{id}
ResetAccountSecret(ctx, id uint) -> *ResetSecretResp
POST /api/v1/accounts/{id}/reset-secret
返回新生成的明文 AppSecret。
三、签名管理(ServiceAuth)
CreateSignature(ctx, req CreateSignatureReq) -> *Signature
POST /api/v1/signatures
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
UserID |
int |
是 | |
AccountID |
*uint |
否 | 绑定账号,为空表示用户全局签名 |
Title |
string |
是 | 中文抬头 |
EnglishName |
string |
是 | 英文标识(用于组装 From 地址) |
Content |
string |
否 | HTML 签名内容 |
Applicant |
string |
否 | 申请人 |
ApplicantInfo |
string |
否 | 申请说明 |
新建默认为 Status=0(待审核)。
ListSignatures(ctx, q SignatureListQuery) -> *PaginationResult[Signature]
GET /api/v1/signatures?page=&page_size=&user_id=&account_id=&status=&keyword=
GetSignature(ctx, id uint) / UpdateSignature / DeleteSignature
GET|PUT|DELETE /api/v1/signatures/{id}
AuditSignature(ctx, id uint, req AuditSignatureReq)
POST /api/v1/signatures/{id}/audit
| 字段 | 类型 | 说明 |
|---|---|---|
Action |
int8 |
1=通过,2=驳回 |
RejectReason |
string |
驳回时建议填写 |
Auditor |
string |
审核人标识 |
四、邮件日志(ServiceAuth)
ListMailLogs(ctx, q MailLogListQuery) -> *PaginationResult[MailLog]
GET /api/v1/mail-logs
| 参数 | 类型 | 说明 |
|---|---|---|
UserID |
*int |
|
AccountID |
*uint |
|
Status |
*int8 |
见 MailLog.Status 枚举 |
StartDate/EndDate |
string |
YYYY-MM-DD |
To |
string |
收件人精确匹配 |
Keyword |
string |
模糊匹配主题或收件人 |
GetMailLog(ctx, id uint) -> *MailLogDetail
GET /api/v1/mail-logs/{id} 返回 MailLog + 正文 Body。
GetMailStats(ctx) -> []MailStatItem
GET /api/v1/mail-logs/stats 按 Status 分组的邮件数统计。
五、配额管理(ServiceAuth)
CreateQuota(ctx, req CreateQuotaReq) -> *MailQuota
POST /api/v1/quotas
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
UserID |
int |
是 | |
AccountID |
uint |
是 | |
QuotaType |
int8 |
是 | 1=总量,2=周期 |
Total |
int |
是 | 额度上限 |
ExpireAt |
string |
否 | YYYY-MM-DD HH:mm:ss |
CycleUnit |
string |
否 | day / week / month / year |
CycleResetAt |
string |
否 | 周期起始时间 |
ListQuotas(ctx, q QuotaListQuery) · GetQuotaSummary(ctx, accountID) · UpdateQuota(ctx, id, req) · DeleteQuota(ctx, id)
UpdateQuotaReq 支持局部更新 Total、Status、ExpireAt、CycleUnit、CycleResetAt。
QuotaListQuery 过滤参数:UserID、AccountID、QuotaType、Status。
六、通道与发信账号(ServiceAuth)
通道 Channel
CreateChannel(ctx, req CreateChannelReq) -> *Channel—POST /api/v1/channelsListChannels(ctx, q ChannelListQuery) -> *PaginationResult[Channel]—GET /api/v1/channelsUpdateChannel(ctx, id, req UpdateChannelReq) -> *Channel—PUT /api/v1/channels/{id}DeleteChannel(ctx, id uint) error—DELETE /api/v1/channels/{id}
CreateChannelReq 字段:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
Code |
string |
是 | 唯一标识(发送邮件用) |
Name |
string |
是 | |
Description |
string |
否 | |
Strategy |
string |
否 | 见 Channel.Strategy 枚举 |
发信账号 SenderAccount
CreateSender(ctx, channelID uint, req CreateSenderReq) -> *SenderAccount—POST /api/v1/channels/{channelID}/sendersListSendersByChannel(ctx, channelID, q SenderListQuery) -> *PaginationResult[SenderAccount]—GET /api/v1/channels/{channelID}/sendersUpdateSender(ctx, id uint, req UpdateSenderReq) -> *SenderAccount—PUT /api/v1/senders/{id}DeleteSender(ctx, id uint) error—DELETE /api/v1/senders/{id}
CreateSenderReq 关键字段:Name、SmtpHost、SmtpPort、SmtpUser、SmtpPassword、SmtpSSL、FromName、FromAddress、DailyLimit、Weight。
七、审核(ServiceAuth)
ListAuditPending(ctx, q AuditPendingQuery) -> *PaginationResult[MailLog]—GET /api/v1/audits/pendingGetAuditPendingDetail(ctx, id uint) -> *MailLogDetail—GET /api/v1/audits/pending/{id}ApproveAudit(ctx, id uint) error—POST /api/v1/audits/{id}/approveRejectAudit(ctx, id uint, req AuditRejectReq) error—POST /api/v1/audits/{id}/rejectBatchApproveAudit(ctx, req BatchAuditApproveReq) error—POST /api/v1/audits/batch/approveBatchRejectAudit(ctx, req BatchAuditRejectReq) error—POST /api/v1/audits/batch/rejectListAuditLogs(ctx, q AuditLogQuery) -> *PaginationResult[MailAudit]—GET /api/v1/audits/logsGetAuditStats(ctx) -> *AuditStats—GET /api/v1/audits/stats
AuditPendingQuery 过滤:AccountID、UserID、Keyword。
AuditLogQuery 过滤:AccountID、UserID、Action、AuditType、StartDate、EndDate。
八、审核规则(ServiceAuth)
CreateAuditRule(ctx, req CreateAuditRuleReq) -> *AuditRule—POST /api/v1/audit-rulesListAuditRules(ctx) -> []AuditRule—GET /api/v1/audit-rulesGetAuditRule(ctx, id uint) -> *AuditRule—GET /api/v1/audit-rules/{id}UpdateAuditRule(ctx, id uint, req UpdateAuditRuleReq) -> *AuditRule—PUT /api/v1/audit-rules/{id}DeleteAuditRule(ctx, id uint) error—DELETE /api/v1/audit-rules/{id}UpdateAuditRuleStatus(ctx, id uint, status int8) -> *AuditRule—PUT /api/v1/audit-rules/{id}/statusTestAuditRule(ctx, req TestAuditRuleReq) -> *TestAuditRuleResp—POST /api/v1/audit-rules/test
CreateAuditRuleReq 字段:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
Name |
string |
是 | |
RuleType |
string |
是 | 见 AuditRule.RuleType 枚举 |
Target |
string |
是 | 见 AuditRule.Target 枚举 |
Condition |
string |
是 | 关键词或正则表达式 |
Action |
int8 |
是 | 见 AuditRule.Action 枚举 |
Priority |
int |
否 | 数字越大优先级越高 |
Remark |
string |
否 |
九、队列(ServiceAuth)
GetQueueStatus(ctx) -> *QueueStatusData—GET /api/v1/queue/statusListQueuePending(ctx, q QueuePendingQuery) -> *PaginationResult[MailLog]—GET /api/v1/queue/pendingCancelQueueItem(ctx, mailLogID uint) error—POST /api/v1/queue/{mailLogID}/cancelRetryQueueItem(ctx, mailLogID uint) error—POST /api/v1/queue/{mailLogID}/retry
QueueStatusData 返回各通道队列长度与延迟队列长度:
type QueueStatusData struct {
Queues map[string]int64 `json:"queues"` // key = channel code
DelayQueue int64 `json:"delay_queue"`
}
十、健康检查(ServiceAuth)
ListCheckLogs(ctx, q CheckLogQuery) -> *PaginationResult[CheckLog]—GET /api/v1/check-logsGetCheckSummary(ctx) -> []SenderHealth—GET /api/v1/check-logs/summaryTriggerCheck(ctx, senderAccountID uint) -> *TriggerCheckResp—POST /api/v1/check-logs/trigger/{senderAccountID}
CheckLogQuery 过滤:SenderAccountID、Received、StartDate��EndDate。
统一返回结构
后端所有接口统一使用:
{ "code": 200, "message": "ok", "data": { /* 业务数据 */ } }
SDK 内部会解包 data 并在非 200 时返回 *APIError:
resp, err := client.SendMail(ctx, req)
if err != nil {
var apiErr *emailcli.APIError
if errors.As(err, &apiErr) {
fmt.Printf("API error: code=%d message=%s\n", apiErr.Code, apiErr.Message)
}
}
分页接口统一包装:
type PaginationResult[T any] struct {
List []T `json:"list"`
Total int64 `json:"total"`
Page int `json:"page"`
PageSize int `json:"page_size"`
}
License
MIT