# go-mail-system
**Repository Path**: louis_xie/go-mail-system
## Basic Information
- **Project Name**: go-mail-system
- **Description**: go mail system
- **Primary Language**: Go
- **License**: Not specified
- **Default Branch**: main
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 1
- **Forks**: 1
- **Created**: 2025-11-13
- **Last Updated**: 2025-11-16
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# Go 邮件系统扩展版
一个基于Golang构建的高可用、可监控的分布式邮件发送系统。该系统采用主备双提供商(AWS SES + SMTP)、异步重试队列和连接池等技术,确保了邮件投递的可靠性和系统的健壮性。
详细的内容介绍全在微信公众号中。干货持续更新,敬请关注「代码扳手」微信公众号:
## 系统架构
本系统是一个典型的微服务架构,由多个协作的组件构成:
```
+------------------+ +---------------------+
| | | |
| HTTP Client |---->| API Server |
| (e.g., curl, web)| | (Gin Framework) |
+------------------+ +----------+----------+
|
| 调用
v
+----------------+-----------+ +--------------------+
| | | |
| Mail Service |<---| Worker (Goroutine) |
| | | |
+------------+-------------+ +---------+----------+
| |
+-----------------v--------------+ +----------v-----------+
| | | |
| Primary: AWS SES Provider | | Secondary: SMTP Queue|
| | | |
+--------------------------------+ +----------------------+
| |
v v
AWS Simple Email Service Redis Stream (Message Queue)
```
## 核心功能
### 1. 双重发送提供商 (Dual Providers)
系统实现了主备两种邮件发送路径:
- **主提供商 ([SESProvider](internal/mail/provider/ses.go#L14-L17))**:
基于 [AWS SES v2 SDK](https://aws.github.io/aws-sdk-go-v2/docs/service/sesv2/),作为首选发送通道。发送失败时会降级到备用方案。
- **备提供商 ([SMTPProvider](internal/mail/provider/smtp.go#L12-L18))**:
基于Go标准库 `net/smtp`,用于处理来自队列的重试请求,也可在SES初始化失败时作为主要发送通道。
通过 `MailProvider` 接口实现了提供商的抽象,使 `MailService` 能够无缝切换。
### 2. 异步重试与死信队列
当主提供商(SES)发送失败时,系统不会立即返回错误,而是将邮件请求持久化到消息队列中进行延迟重试。
- **生产者 ([RedisStream.Produce](internal/queue/redis_stream.go#L70-L91))**:
`MailService.Send` 方法在SES发送失败后,会调用此方法将序列化的 `MailRequest` 发送到Redis Stream,并设置30分钟的延迟。
- **消费者 ([Worker.Run](internal/worker/worker.go#L35-L69))**:
后台工作协程持续从队列中消费消息,使用SMTP提供商进行重试。
- **智能重试策略**:
- 消息会携带 `attempt` 计数器,记录重试次数。
- 达到最大重试次数(默认3次)或遇到永久性错误时,消息会被移动到死信队列(DLQ),防止无限循环。
### 3. 错误分类与降级
系统对错误进行了精确分类,这是实现智能路由的关键:
- **临时性错误 (`*TemporaryError`)**:
如网络超时、服务器繁忙。这类错误会触发降级到队列进行重试。
- **永久性错误 (`*PermanentError`)**:
如邮箱地址不存在、权限被拒。这类错误会直接返回客户端,避免无意义的重试。
错误分类发生在每个提供商的 `SendEmail` 方法内部。
### 4. 高级特性
- **模板引擎**: 支持使用Go模板语法动态渲染邮件内容,通过 `TemplateRegistry` 注册和管理模板。
- **连接池**: 使用 `ConnectionPool` 限制并发邮件发送的数量,保护下游服务。
- **度量监控**: 集成Prometheus,暴露 `mail_attempts_total`, `mail_success_total` 等指标,可通过 `/metrics` 端点访问。
- **优雅关闭**: 主程序监听SIGINT/SIGTERM信号,能够平滑地停止HTTP服务器和后台工作协程。
## 快速开始
1. **配置**:
复制 `config/config.yaml.example` 为 `config/config.yaml` 并填写你的AWS和SMTP凭据。
2. **启动**:
```bash
go run cmd/main.go
```
3. **发送邮件**:
```bash
curl -X POST http://localhost:8080/send \
-H "Content-Type: application/json" \
-d '{"to": "user@example.com", "subject": "Hello", "body": "
Test email
"}' ``` 4. **查看指标**: 访问 `http://localhost:8080/metrics` 查看Prometheus格式的性能数据。 ## 目录结构 ``` go-mail-system/ ├── cmd/ │ └── main.go # 应用入口,初始化所有组件并启动服务器 ├── config/ │ └── config.yaml # YAML配置文件 ├── internal/ │ ├── api/ # HTTP API 路由 (Gin) │ ├── config/ # 配置加载逻辑 │ ├── mail/ # 邮件核心业务逻辑 │ │ ├── provider/ # 具体的邮件提供商 (SES, SMTP) │ │ ├── service.go # 核心服务,协调各组件 │ │ ├── types.go # 公共数据类型和接口定义 │ │ └── ... │ ├── queue/ # 基于Redis Stream的消息队列实现 │ ├── worker/ # 后台工作协程,负责消费队列 │ └── ... # logging, metrics等 └── go.mod # Go模块定义 ```