FoskyM/tiny-mail

★ 3Forks 0TypeScriptGitHub ↗Compare

README

Tiny Mail

轻量级临时邮箱收件系统,单个 Docker 容器部署,支持多域名、API 鉴权、临时邮箱生成。

功能特性

  • 两种收件模式:内置 SMTP 服务器 或 Cloudflare Email Worker 转发
  • REST API 查询/管理邮件
  • 临时邮箱地址生成,支持自定义前缀和过期时间
  • 多域名绑定
  • API Key 鉴权保护
  • SQLite 持久化存储(sql.js,无需额外数据库)
  • React + TailwindCSS 前端界面
  • 单容器 Docker 部署

快速开始

Docker 部署(推荐)

  1. 复制环境变量文件并修改配置:
cp .env.example .env
  1. 编辑 .env 文件:
AUTH_KEY=your-secret-key-here
DOMAINS=mail.example.com,tmp.example.org
HTTP_PORT=3000
SMTP_PORT=25
MAIL_MODE=smtp
  1. 启动服务:
docker compose up -d

服务启动后:

  • Web 界面:http://localhost:3000
  • SMTP 服务:端口 25

本地部署

无需 Docker,直接在本地运行。服务启动时会自动读取项目根目录的 .env 文件。

# 1. 复制并编辑环境变量
cp .env.example .env
# 编辑 .env 设置 AUTH_KEY、DOMAINS 等

# 2. 安装依赖
npm run install:all

# 3. 构建
npm run build

# 4. 启动
npm start

服务启动后:

  • Web 界面:http://localhost:3000
  • SMTP 服务:端口 25(smtp 模式下)

本地开发

# 安装依赖
npm run install:all

# 确保 .env 已配置

# 启动后端(自动读取 .env)
npm run dev:server

# 启动前端(另一个终端)
npm run dev:web

环境变量

变量 说明 默认值
AUTH_KEY API 鉴权密钥(必填) -
DOMAINS 允许接收邮件的域名,逗号分隔 localhost
HTTP_PORT HTTP 服务端口 3000
SMTP_PORT SMTP 服务端口(仅 smtp 模式) 25
DATA_DIR 数据存储目录 ./data
MAIL_MODE 收件模式:smtp 或 cf-worker smtp

收件模式

Tiny Mail 支持两种收件模式,通过 MAIL_MODE 环境变量切换。

模式一:SMTP(默认)

内置 SMTP 服务器直接接收邮件。需要服务器 25 端口对外开放。

MAIL_MODE=smtp
SMTP_PORT=25

适用于:有独立服务器、25 端口未被封禁的场景。

模式二:Cloudflare Email Worker

通过 Cloudflare Email Routing + Worker 转发邮件到 Tiny Mail 的 HTTP 接口。不需要开放 25 端口,适合大多数云服务器。

MAIL_MODE=cf-worker

配置步骤:

1. 启用 Email Routing

  • 登录 Cloudflare Dashboard
  • 选择你的域名 → 左侧菜单点击 Email → Email Routing
  • 点击 Get started,按提示完成启用(Cloudflare 会自动添加所需的 MX 和 TXT 记录)

2. 创建并部署 Worker

方式 A:通过命令行部署(推荐)

cd worker
npm install

# 修改 wrangler.toml 中的 TINY_MAIL_URL 为你的 Tiny Mail 服务地址
# 例如:TINY_MAIL_URL = "https://tiny-mail.example.com"

# 设置密钥(与 .env 中的 AUTH_KEY 一致)
npx wrangler secret put AUTH_KEY

# 部署到 Cloudflare
npm run deploy

方式 B:通过 Cloudflare 控制台手动创建

如果不想在本地安装 wrangler,可以直接在 Cloudflare 后台操作:

  1. 进入 Cloudflare Dashboard → Workers & Pages → Create
  2. 选择 Create Worker,命名为 tiny-mail-worker,点击 Deploy 先创建一个空 Worker
  3. 进入刚创建的 Worker → Settings → Variables and Secrets:
    • 添加变量 TINY_MAIL_URL,值为你的 Tiny Mail 服务地址(如 https://tiny-mail.example.com)
    • 添加密钥 AUTH_KEY,值与 .env 中的 AUTH_KEY 一致(点击 Encrypt 加密存储)
  4. 进入 Worker → Edit Code,将编辑器中的代码替换为以下内容:
export default {
  async email(message, env, ctx) {
    const to = message.to;
    const url = `${env.TINY_MAIL_URL}/api/incoming?to=${encodeURIComponent(to)}`;

    const response = await fetch(url, {
      method: "POST",
      headers: {
        "Content-Type": "application/octet-stream",
        "Authorization": `Bearer ${env.AUTH_KEY}`,
      },
      body: await new Response(message.raw).arrayBuffer(),
    });

    if (!response.ok) {
      const text = await response.text();
      console.log(`Failed to deliver mail to ${to}: ${response.status} ${text}`);
      message.setReject(`Failed to process email: ${response.status}`);
    } else {
      console.log(`Mail delivered to ${to}`);
    }
  },
};
  1. 点击 Deploy 保存并部署

3. 配置 Email Routing 规则

  • 进入 Cloudflare Dashboard → 你的域名 → Email → Email Routing → Routing rules
  • 配置方式(二选一):
    • Catch-all(接收所有邮件):在 Catch-all address 行点击 Edit,Action 选择 Send to a Worker,选择 tiny-mail-worker
    • 指定地址:点击 Create address,填写自定义地址,Action 选择 Send to a Worker,选择 tiny-mail-worker

4. 验证

  • 确保 .env 中 DOMAINS 包含你在 Cloudflare 配置的域名
  • 发送一封测试邮件到配置的地址,在 Tiny Mail 前端查看是否收到
  • 如果未收到,可在 Cloudflare Dashboard → Workers → tiny-mail-worker → Logs 中查看错误日志

工作流程:

发件方 → Cloudflare Email Routing → Worker → POST /api/incoming → Tiny Mail 存储

DNS 配置

SMTP 模式

使用 SMTP 模式时,需要自行配置 DNS 让外部邮件服务器能找到你的服务器。

要让外部邮件(如 Gmail、QQ 邮箱)能发送到你的临时邮箱,需要正确配置 DNS 记录。邮件投递依赖 MX(Mail Exchange)记录,发件方会查询收件域名的 MX 记录来确定邮件该投递到哪台服务器。

场景一:使用主域名收件

想让 [email protected] 能收到邮件:

DNS 记录:

类型 主机记录 记录值 说明
A mail 1.2.3.4 指向你运行 Tiny Mail 的服务器 IP
MX @ mail.example.com 告诉发件方:发往 example.com 的邮件投递到 mail.example.com

MX 记录的优先级填 10(数字越小优先级越高,单台服务器随意填即可)。

.env 配置:

DOMAINS=example.com

效果: 任何人发邮件到 [email protected],Tiny Mail 都会接收。


场景二:使用子域名收件

想让 [email protected] 能收到邮件(不影响主域名的邮件服务):

DNS 记录:

类型 主机记录 记录值 说明
A mail 1.2.3.4 指向你的服务器 IP
MX mail mail.example.com 发往 mail.example.com 的邮件投递到自身

.env 配置:

DOMAINS=mail.example.com

场景三:多域名同时收件

同时用 example.com 和 tmp.example.org 收件:

DNS 记录(example.com):

类型 主机记录 记录值
A mail 1.2.3.4
MX @ mail.example.com

DNS 记录(example.org):

类型 主机记录 记录值
MX tmp mail.example.com

多个域名的 MX 可以指向同一台服务器。

.env 配置:

DOMAINS=example.com,tmp.example.org

验证配置

DNS 记录生效后(通常几分钟到 48 小时),可以用以下命令验证:

# 查询 MX 记录
dig MX example.com
# 或
nslookup -type=mx example.com

# 测试 SMTP 连通性
telnet mail.example.com 25

注意事项

  • 服务器的 25 端口必须对外开放(部分云服务商默认封禁 25 端口,需要申请解封或使用其他端口)
  • 如果使用非标准端口(如 2525),外部邮件服务器无法投递(MX 标准只支持 25 端口),仅适合内部测试
  • 建议同时配置 SPF 记录(虽然 Tiny Mail 只收不发,但有助于减少被误判为垃圾邮件源):
    example.com.  TXT  "v=spf1 mx -all"
    

Cloudflare Worker 模式

使用 Cloudflare Worker 模式时,DNS 由 Cloudflare 管理,无需手动配置 MX 记录。

Cloudflare 启用 Email Routing 后会自动添加所需的 MX 和 TXT 记录。你只需要:

  1. 域名的 DNS 托管在 Cloudflare
  2. 在 Cloudflare Dashboard 中启用 Email Routing(会自动配置 MX 记录)
  3. 配置路由规则将邮件转发到 Worker

技术栈

  • 后端: Node.js + TypeScript + Express + smtp-server
  • 存储: SQLite (sql.js)
  • 前端: React 18 + TailwindCSS 3 + Vite
  • 部署: Docker

项目结构

tiny-mail/
├── server/              # 后端服务
│   └── src/
│       ├── index.ts     # 入口
│       ├── config.ts    # 配置管理
│       ├── smtp.ts      # SMTP 服务器
│       ├── api.ts       # REST API 路由
│       ├── store.ts     # SQLite 数据层
│       └── types.ts     # 类型定义
├── web/                 # 前端
│   └── src/
│       ├── App.tsx      # 主组件
│       ├── api.ts       # API 调用
│       └── components/  # UI 组件
├── worker/              # Cloudflare Email Worker
│   ├── src/index.ts     # Worker 入口
│   ├── wrangler.toml    # Wrangler 配置
│   └── package.json
├── .env.example         # 环境变量模板
├── Dockerfile
├── docker-compose.yml
└── API.md               # 接口文档

License

MIT

Contributors

FoskyM

Issues