|
@@ -1,12 +1,12 @@
|
|
|
# MailHub
|
|
# MailHub
|
|
|
|
|
|
|
|
-MailHub 是一个 Docker 化的发信域名管理面板和发送 API。它负责:
|
|
|
|
|
|
|
+MailHub 是一个 Docker 化的多用户发信域名管理面板、SMTP Submission 服务和发送 API。它负责:
|
|
|
|
|
|
|
|
-- 添加发信域名并生成验证 TXT。
|
|
|
|
|
-- 为每个域名生成 DKIM key 和 DNS 记录。
|
|
|
|
|
-- 读取当前公网 DNS,合并已有 SPF 和第三方发信 include。
|
|
|
|
|
-- 给出 SPF、DKIM、DMARC、PTR、发信主机 A 记录的状态和建议。
|
|
|
|
|
-- 通过内部 Postfix 出站队列发送邮件,API 会先给邮件加 DKIM 签名。
|
|
|
|
|
|
|
+- 开放注册用户账号,并隔离每个用户的域名、SMTP 凭据、DNS API 凭据和发送记录。
|
|
|
|
|
+- 为每个发信域名生成验证 TXT、DKIM key、SPF、DMARC、发信主机 A 记录建议。
|
|
|
|
|
+- 支持 Cloudflare、阿里云 DNS、腾讯云 DNSPod API,一键写入基础发信 DNS。
|
|
|
|
|
+- 读取公网 DNS,检查 SPF、DKIM、DMARC、PTR、发信主机 A 记录状态。
|
|
|
|
|
+- 通过内部 Postfix 出站队列发送邮件,并按发件域名加 DKIM 签名。
|
|
|
|
|
|
|
|
## 运行
|
|
## 运行
|
|
|
|
|
|
|
@@ -17,127 +17,102 @@ docker compose ps
|
|
|
docker compose logs -f app postfix
|
|
docker compose logs -f app postfix
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-管理面板默认监听宿主机 `127.0.0.1:3025`,nginx 已反代到 `mail-send.ss5.xyz`。
|
|
|
|
|
|
|
+管理面板默认监听宿主机 `127.0.0.1:3025`,nginx 可反代到公网域名。
|
|
|
|
|
|
|
|
-面板使用 HTML 登录页和 Cookie 会话。登录账号和 API Token 在 `.env`:
|
|
|
|
|
|
|
+## 账号和权限
|
|
|
|
|
|
|
|
-- `ADMIN_USER`
|
|
|
|
|
-- `ADMIN_PASSWORD`
|
|
|
|
|
-- `API_TOKEN`
|
|
|
|
|
-- `SESSION_SECRET` 可选;不设置时会从管理密码和 API Token 派生。
|
|
|
|
|
|
|
+- 首次启动会根据 `.env` 中的 `ADMIN_USER`、`ADMIN_EMAIL`、`ADMIN_PASSWORD` 创建或修复一个 admin 用户。
|
|
|
|
|
+- 普通用户可在 `/register` 开放注册。
|
|
|
|
|
+- 用户只能看到自己的域名、SMTP 凭据、DNS 凭据、API Token 和发送记录。
|
|
|
|
|
+- admin 用户可在网页里修改系统业务设置、查看用户列表、禁用或启用用户。
|
|
|
|
|
|
|
|
-## SMTP 公网发信
|
|
|
|
|
|
|
+## SMTP 发信
|
|
|
|
|
|
|
|
-MailHub 现在提供公网 SMTP Submission。所有发信端口都需要 SMTP AUTH,未认证不会转发邮件,避免开放中继。
|
|
|
|
|
|
|
+MailHub 提供公网 SMTP Submission。所有发信端口都需要 SMTP AUTH,未认证不会转发邮件,避免开放中继。
|
|
|
|
|
|
|
|
连接信息:
|
|
连接信息:
|
|
|
|
|
|
|
|
```txt
|
|
```txt
|
|
|
-Host: in.ss5.xyz
|
|
|
|
|
|
|
+Host: 由 SUBMISSION_HOST 配置,例如 in.example.com
|
|
|
Port 25: SMTP + STARTTLS + AUTH
|
|
Port 25: SMTP + STARTTLS + AUTH
|
|
|
Port 587: SMTP Submission + STARTTLS + AUTH
|
|
Port 587: SMTP Submission + STARTTLS + AUTH
|
|
|
Port 465: SMTPS implicit TLS + AUTH
|
|
Port 465: SMTPS implicit TLS + AUTH
|
|
|
Port 2525: SMTP + STARTTLS + AUTH
|
|
Port 2525: SMTP + STARTTLS + AUTH
|
|
|
-Username: 在面板左侧“SMTP 凭据”中配置
|
|
|
|
|
-Password: 在面板左侧“SMTP 凭据”中配置,保存后不会回显
|
|
|
|
|
|
|
+Username: 用户在网页“SMTP 凭据”中配置,可复制
|
|
|
|
|
+Password: 用户在网页“SMTP 凭据”中配置,可复制
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-默认 `SUBMISSION_ALLOW_INSECURE_AUTH=false`,也就是 `25/587/2525` 必须先 STARTTLS 才允许 AUTH;`465` 连接建立时就是 TLS。
|
|
|
|
|
|
|
+SMTP 密码会同时保存哈希和服务端加密密文:哈希用于认证,加密密文用于用户本人在网页复制。旧数据如果只有哈希,无法反解,需要用户重新设置一次密码后才能复制。
|
|
|
|
|
|
|
|
-`.env` 中的 `SUBMISSION_USERNAME` 和 `SUBMISSION_PASSWORD` 只用于首次初始化数据库。初始化后以面板保存的 SMTP 凭据为准,修改后无需重启。
|
|
|
|
|
|
|
+`.env` 中的 `SUBMISSION_USERNAME` 和 `SUBMISSION_PASSWORD` 只用于首次给 admin 初始化 SMTP 凭据。初始化后以每个用户在面板保存的 SMTP 凭据为准,修改后无需重启。
|
|
|
|
|
|
|
|
-当前 TLS 证书位于:
|
|
|
|
|
|
|
+## DNS API 一键配置
|
|
|
|
|
|
|
|
-```txt
|
|
|
|
|
-certs/mail-send.ss5.xyz.crt
|
|
|
|
|
-certs/mail-send.ss5.xyz.key
|
|
|
|
|
-```
|
|
|
|
|
-
|
|
|
|
|
-这是一张自签名证书,只用于先把协议跑通。正式公网使用建议替换为包含 `in.ss5.xyz` 的可信证书,然后重启:
|
|
|
|
|
-
|
|
|
|
|
-```bash
|
|
|
|
|
-docker compose up -d app
|
|
|
|
|
-```
|
|
|
|
|
-
|
|
|
|
|
-## 当前默认配置
|
|
|
|
|
-
|
|
|
|
|
-```env
|
|
|
|
|
-MAIL_HOSTNAME=in.ss5.xyz
|
|
|
|
|
-SENDING_IP=8.231.54.11
|
|
|
|
|
-DEFAULT_SPF_MECHANISMS=include:spf.mailjet.com
|
|
|
|
|
-SMTP_HOST=postfix
|
|
|
|
|
-SMTP_PORT=25
|
|
|
|
|
-```
|
|
|
|
|
-
|
|
|
|
|
-如果实际出站 IP 不是 `8.231.54.11`,需要同步修改 `.env` 和面板里对应域名的“发信 IP”。
|
|
|
|
|
-
|
|
|
|
|
-## DNS 重点
|
|
|
|
|
-
|
|
|
|
|
-SPF 只能保留一条 `v=spf1` TXT。不要为了 Mailjet、飞书、本机发信分别添加多条 SPF;要合并为一条。
|
|
|
|
|
-
|
|
|
|
|
-## in.ss5.xyz 测试记录
|
|
|
|
|
-
|
|
|
|
|
-请为 `in.ss5.xyz` 添加或确认以下记录:
|
|
|
|
|
-
|
|
|
|
|
-```txt
|
|
|
|
|
-in.ss5.xyz. A 8.231.54.11
|
|
|
|
|
-```
|
|
|
|
|
-
|
|
|
|
|
-```txt
|
|
|
|
|
-_mailhub.in.ss5.xyz. TXT mailhub-verification=9e45358e44624ce991c655e9c19b847f8c98
|
|
|
|
|
-```
|
|
|
|
|
|
|
+用户可在网页“DNS API”中保存以下服务商凭据:
|
|
|
|
|
|
|
|
-```txt
|
|
|
|
|
-mh202607._domainkey.in.ss5.xyz. TXT v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuaQrn0IrsNDVsbn160yOR7DMBaOkXegtlhUCvHYdKCy5Aa/rUcGvUI3gbLoo6m9QEiLs3EAJo29Y9RBbv3lQn/PvAKtfrTuT6Zo1BfcIhe9wJvipgAkH+hFmB4aNZ7MMTKE7vOztOHJooyyiJSHhgBqCVSG4fP7hr+vz5X8kAPXfasQnChHAmA1zM/m41/7qyo78C4pbqBiMAkkGV0zwNhaR1Fy1hdKx4IGpmrMrm5/sye4MK8dMD3jXooJ1Efv+Sh0HjpvKrN8zcxqvNDPusmIgZBxCN49m4R0dYsldK/v/KOeQJVfd+B6U0/2O8p2JHpd5Y1eaJjbREvFsKI30aQIDAQAB
|
|
|
|
|
-```
|
|
|
|
|
-
|
|
|
|
|
-```txt
|
|
|
|
|
-in.ss5.xyz. TXT v=spf1 ip4:8.231.54.11 a:in.ss5.xyz include:spf.mailjet.com ~all
|
|
|
|
|
-```
|
|
|
|
|
|
|
+- Cloudflare:API Token,建议只授予目标 Zone 的 DNS Edit 权限;可选 Zone ID。
|
|
|
|
|
+- 阿里云 DNS:AccessKeyId 和 AccessKeySecret。
|
|
|
|
|
+- 腾讯云 DNSPod:SecretId 和 SecretKey。
|
|
|
|
|
|
|
|
-```txt
|
|
|
|
|
-_dmarc.in.ss5.xyz. TXT v=DMARC1; p=none; rua=mailto:dmarc@in.ss5.xyz; adkim=s; aspf=s; pct=100
|
|
|
|
|
-```
|
|
|
|
|
-
|
|
|
|
|
-还需要在 IP 服务商控制台设置反向解析:
|
|
|
|
|
-
|
|
|
|
|
-```txt
|
|
|
|
|
-8.231.54.11 PTR in.ss5.xyz
|
|
|
|
|
-```
|
|
|
|
|
|
|
+域名绑定 DNS 凭据后,点击“一键配置 DNS”会写入或更新:
|
|
|
|
|
|
|
|
-当前检测到 `8.231.54.11` 的 PTR 仍是 `11.54.231.8.bc.googleusercontent.com`。
|
|
|
|
|
|
|
+- `_mailhub.<domain>` TXT 验证记录。
|
|
|
|
|
+- `<selector>._domainkey.<domain>` DKIM TXT。
|
|
|
|
|
+- 根域 SPF TXT,并合并为一条 `v=spf1`。
|
|
|
|
|
+- `_dmarc.<domain>` DMARC TXT。
|
|
|
|
|
+- 发信主机 A 记录。
|
|
|
|
|
|
|
|
-当前 `ss5.xyz` 已检测到两条 SPF,建议合并为:
|
|
|
|
|
|
|
+PTR 反向解析只检测和提示,通常必须在云服务器或 IP 服务商控制台配置。
|
|
|
|
|
|
|
|
-```txt
|
|
|
|
|
-v=spf1 include:spf.mailjet.com include:_netblocks.m.feishu.cn include:spf.ss5.xyz.com include:spf.97admin.com ip4:8.231.54.11 a:ali.ss5.xyz -all
|
|
|
|
|
-```
|
|
|
|
|
|
|
+## 网页化系统设置
|
|
|
|
|
|
|
|
-当前测试发信主机使用 `in.ss5.xyz`,它应当解析到 `8.231.54.11`。二者需要保持对齐:
|
|
|
|
|
|
|
+admin 可在面板中修改以下业务设置:
|
|
|
|
|
|
|
|
-- 如果由当前 Docker 服务器发信,把 `in.ss5.xyz` A 记录和 IP 的 PTR 都指向 `8.231.54.11`。
|
|
|
|
|
-- 如果实际由 `39.108.92.239` 发信,把 `.env` 和域名设置里的 `SENDING_IP` 改为 `39.108.92.239`。
|
|
|
|
|
|
|
+- `APP_BASE_URL`
|
|
|
|
|
+- `MAIL_HOSTNAME`
|
|
|
|
|
+- `SENDING_IP`
|
|
|
|
|
+- `DEFAULT_SPF_MECHANISMS`
|
|
|
|
|
+- `DMARC_POLICY`
|
|
|
|
|
+- `DMARC_RUA`
|
|
|
|
|
+- `SEND_REQUIRES_VERIFIED`
|
|
|
|
|
|
|
|
-PTR 反向解析需要在云厂商或 IP 服务商控制台设置,普通域名 DNS 控制台不能设置。
|
|
|
|
|
|
|
+基础设施设置仍通过 `.env` 配置并需要重启,例如监听端口、数据目录、SMTP 中继、TLS 证书路径和 `SESSION_SECRET`。
|
|
|
|
|
|
|
|
## 发送 API
|
|
## 发送 API
|
|
|
|
|
|
|
|
|
|
+每个用户在面板生成自己的发送 API Token。Token 只在创建时完整显示并自动复制,之后列表只显示前缀。
|
|
|
|
|
+
|
|
|
```bash
|
|
```bash
|
|
|
-curl -X POST http://mail-send.ss5.xyz/api/send \
|
|
|
|
|
- -H "Authorization: Bearer <API_TOKEN>" \
|
|
|
|
|
|
|
+curl -X POST http://mail-send.example.com/api/send \
|
|
|
|
|
+ -H "Authorization: Bearer <USER_API_TOKEN>" \
|
|
|
-H "Content-Type: application/json" \
|
|
-H "Content-Type: application/json" \
|
|
|
-d '{
|
|
-d '{
|
|
|
- "from": "noreply@ss5.xyz",
|
|
|
|
|
|
|
+ "from": "noreply@example.com",
|
|
|
"to": "user@example.com",
|
|
"to": "user@example.com",
|
|
|
"subject": "Hello from MailHub",
|
|
"subject": "Hello from MailHub",
|
|
|
- "text": "Signed with DKIM and queued by Postfix."
|
|
|
|
|
|
|
+ "text": "Signed with DKIM and queued by MailHub."
|
|
|
}'
|
|
}'
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-SMTP 发信时,`Host` 使用 `in.ss5.xyz`。任意已添加并完成 DNS 配置的发信域名,都可以使用该域名下任意邮箱地址作为 `From`,例如 `notice@example.com`、`billing@example.com`、`noreply@example.com`。本服务会按 `From` 所属域名查找 DKIM 私钥并签名。
|
|
|
|
|
|
|
+发送时会校验 `From` 所属域名必须归当前 Token 所属用户所有。`.env` 中的 `API_TOKEN` 仅作为旧版 admin 兼容发送 token,新用户应使用网页生成的用户级 Token。
|
|
|
|
|
+
|
|
|
|
|
+## 测试
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+npm test
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+测试覆盖:
|
|
|
|
|
+
|
|
|
|
|
+- 旧 SQLite 数据迁移到 admin 用户。
|
|
|
|
|
+- 多用户域名、发送记录、SMTP 凭据、API Token 隔离。
|
|
|
|
|
+- SMTP 密码可复制明文与哈希认证。
|
|
|
|
|
+- Cloudflare、阿里云 DNS、腾讯云 DNSPod 的 mocked API 写入流程。
|
|
|
|
|
|
|
|
-生产发信前确认:
|
|
|
|
|
|
|
+## 生产检查
|
|
|
|
|
|
|
|
|
|
+- 修改默认 admin 密码并设置足够长的 `SESSION_SECRET`。
|
|
|
|
|
+- 不要提交 `.env`、SQLite 数据库、证书私钥或 DNS/API 密钥。
|
|
|
- 服务器出站 25 端口没有被云厂商拦截。
|
|
- 服务器出站 25 端口没有被云厂商拦截。
|
|
|
- 服务器入站 `25/465/587/2525` 已在云防火墙和系统防火墙放行。
|
|
- 服务器入站 `25/465/587/2525` 已在云防火墙和系统防火墙放行。
|
|
|
- SPF、DKIM、DMARC 均通过。
|
|
- SPF、DKIM、DMARC 均通过。
|