Files

155 lines
7.7 KiB
Markdown
Raw Permalink Normal View History

2026-06-28 19:42:35 +08:00
# kiri-mail-server 架构设计文档
## 一、功能概述
基于 PHP + Swoole 的生产级邮件服务器。
### Phase 1 (已完成): SMTP 收信
- SMTP 协议接收邮件 (RFC 5321)
- MIME 邮件解析
- Maildir 存储
### Phase 2 (已完成): 邮件队列与外发投递
- Redis 持久化发送队列
- DNS MX 记录查询
- SMTP 客户端外发投递
- 指数退避重试策略
- 死信队列
- 退信生成
- 速率限制 (令牌桶)
## 二、架构组件
```
┌──────────────────────────────────────────────────────┐
│ SmtpServer │
│ (Swoole TCP Server :25) │
├──────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌────────────┐ ┌───────────────┐ │
│ │ SmtpSession │ │ MailParser │ │ MaildirStorage │ │
│ │ (收信会话) │ │ (解析邮件) │ │ (本地存储) │ │
│ └──────┬──────┘ └────────────┘ └───────────────┘ │
│ │ │
│ │ 远程域名 → 入队 │
│ ▼ │
│ ┌─────────────────┐ │
│ │ MailQueue │ │
│ │ (Redis 持久化队列) │ │
│ └────────┬────────┘ │
│ │ │
└───────────┼────────────────────────────────────────────┘
┌───────────▼────────────────────────────────────────────┐
│ OutboundDelivery │
│ (外发投递进程) │
├─────────────────────────────────────────────────────────┤
│ │
│ ┌──────────┐ ┌──────────┐ ┌───────────────┐ │
│ │DnsResolver│ │SmtpClient │ │ RateLimiter │ │
│ │(MX 查询) │ │(远程投递) │ │ (速率控制) │ │
│ └──────────┘ └──────────┘ └───────────────┘ │
│ │
│ 重试策略: 60s → 300s → 900s → 1800s → 3600s → 死信 │
│ │
└─────────────────────────────────────────────────────────┘
```
## 三、邮件投递流程
```
┌──────────┐
│ SMTP 客户端│
│ (MUA/MSA) │
└─────┬─────┘
│ 连接 :25/:587
┌──────────────────┐
│ SmtpServer │
│ (接收邮件) │
└────────┬─────────┘
┌─────────▼─────────┐
│ 收件人域名判断 │
└────┬──────────┬───┘
│ │
本地域名 │ │ 远程域名
▼ ▼
┌──────────┐ ┌──────────┐
│ Maildir │ │MailQueue │
│ 本地存储 │ │Redis 队列 │
└──────────┘ └────┬─────┘
┌────────────────┐
│OutboundDelivery │
│ 外发投递进程 │
└───────┬────────┘
┌─────────────▼─────────────┐
│ 投递结果 │
└──┬──────────┬──────────┬──┘
│ │ │
成功 │ 临时失败│ 永久失败│
▼ ▼ ▼
┌──────┐ ┌──────┐ ┌──────────┐
│ 移除 │ │ 重试 │ │ 生成退信 │
└──────┘ └──────┘ └──────────┘
```
## 四、Redis 数据结构
```
mail:queue:outbound — ZSET, score=下次尝试时间, member=队列ID
mail:queue:outbound:{id} — Hash, 邮件元数据
mail:queue:outbound:dead — ZSET, 死信队列
mail:dns:mx:{domain} — String(JSON), MX 查询缓存 TTL 300s
mail:ratelimit:global — String(INT), 全局速率计数器
mail:ratelimit:domain:{d} — String(INT), 域名速率计数器
```
## 五、目录结构
```
kiri-mail-server/
├── composer.json
├── DESIGN.md
├── README.md
├── config/
│ └── mail.php
├── src/
│ ├── SmtpServer.php # Swoole TCP 服务器 (收信)
│ ├── SmtpSession.php # SMTP 会话状态机
│ ├── SmtpProtocol.php # 协议命令解析
│ ├── SmtpResponse.php # 响应构建器
│ ├── SmtpClient.php # SMTP 客户端 (发信)
│ ├── SmtpCommand.php # 命令值对象
│ ├── SmtpDeliveryResult.php # 投递结果值对象
│ ├── MailParser.php # MIME 解析
│ ├── MailMessage.php # 邮件消息
│ ├── MailQueue.php # Redis 邮件队列
│ ├── DnsResolver.php # DNS MX 解析
│ ├── RateLimiter.php # 速率限制器
│ ├── OutboundDelivery.php # 外发投递调度
│ ├── OutboundDeliveryProcess.php # 外发投递进程
│ ├── SmtpServerProcess.php # 收信进程
│ ├── MailServerProviders.php # Provider
│ ├── Storage/
│ │ ├── StorageInterface.php
│ │ └── MaildirStorage.php
│ └── Auth/
│ ├── AuthInterface.php
│ └── SimpleAuth.php
└── tests/
```
## 六、进程部署
```php
// config/servers.php
'process' => [
\Kiri\MailServer\SmtpServerProcess::class, // 收信 :25
\Kiri\MailServer\OutboundDeliveryProcess::class, // 外发投递
],
```