Files
mail-rs/README.md
2026-04-25 21:01:51 +08:00

8.7 KiB
Raw Blame History

多邮箱帐号收发系统

一个基于 Node.js + Express + SQLite 的多邮箱工作台,支持在网页中统一管理多个邮箱渠道与邮箱帐号,进行收信、查看邮件、发信,以及通过 API 调用邮件能力。

功能特性

  • 支持配置多个邮箱渠道,如 QQ 邮箱、163 邮箱和自定义 IMAP/SMTP 渠道
  • 支持导入邮箱帐号与授权码
  • 三栏式 Web 界面:邮箱帐号、邮件列表、邮件详情
  • 支持网页写邮件、发邮件、查看邮件详情
  • 支持拉取多文件夹邮件,不限于 INBOX
  • 支持按需补拉单封邮件正文,避免全量同步过慢
  • 支持批量导入导出邮箱信息
  • 支持访问密码保护,未输入密码无法进入功能页面
  • 支持 API Token 模式,方便纯接口调用
  • 提供 API 用于发邮件、获取邮件列表、获取最新一封邮件

技术栈

  • Node.js
  • Express
  • SQLite better-sqlite3
  • SMTP nodemailer
  • IMAP imapflow
  • 前端:原生 HTML / CSS / JavaScript

目录结构

mail-sr/
├── public/
│   ├── index.html
│   ├── styles.css
│   └── app.js
├── db.js
├── mailService.js
├── server.js
├── Dockerfile
├── docker-compose.yml
└── README.md

本地启动

1. 安装依赖

npm install

2. 配置环境变量

cp .env.example .env

默认环境变量:

PORT=3000
DB_PATH=./mail.db
APP_PASSWORD=change-this-password
API_TOKEN=change-this-token

说明:

  • APP_PASSWORD 用于控制页面和 API 访问
  • 设置后,必须先在登录页输入正确密码才能进入系统
  • 如果留空,则不启用密码保护
  • API_TOKEN 用于纯 API 调用认证
  • 设置后,可以通过请求头直接访问业务 API无需网页登录
  • 如果 APP_PASSWORDAPI_TOKEN 同时存在,则满足任意一种认证方式即可访问 API

3. 启动服务

npm start

访问地址:http://localhost:3000

Docker 部署

项目已经提供 Dockerfiledocker-compose.yml,可以直接用 Docker Compose 部署。

1. 准备环境变量

cp .env.example .env

如果你不需要额外环境变量,默认配置即可。

如果启用访问密码,请在 .env 中设置:

APP_PASSWORD=your-strong-password

如果启用 API Token请在 .env 中设置:

API_TOKEN=your-strong-api-token

2. 构建并启动

docker compose up -d --build

启动后访问:http://localhost:3000

3. 停止服务

docker compose down

4. 查看日志

docker compose logs -f

5. 数据持久化

Docker Compose 默认使用命名卷 mail-sr-data 持久化 SQLite 数据库,容器重建后数据不会丢失。

容器内数据库路径:

/data/mail.db

内置邮箱渠道

系统默认会初始化以下渠道:

  • QQ邮箱
    • IMAP: imap.qq.com:993
    • SMTP: smtp.qq.com:465
  • 163邮箱
    • IMAP: imap.163.com:993
    • SMTP: smtp.163.com:465

说明:通常需要在邮箱后台开启 IMAP/SMTP并使用授权码而不是邮箱登录密码。

Web 使用说明

0. 登录保护

如果 .env 中设置了 APP_PASSWORD,打开首页后会先进入登录页。

  • 输入正确密码后,服务端会写入 HttpOnly Cookie
  • 后续页面请求会基于该 Cookie 校验访问权限
  • 点击左下角退出按钮可清除登录状态

1. 渠道管理

在设置弹窗中可以新增渠道,填写:

  • 渠道名称
  • 渠道标识 code
  • IMAP 主机、端口、是否 SSL
  • SMTP 主机、端口、是否 SSL

2. 单个邮箱帐号导入

在设置弹窗中填写:

  • 渠道
  • 邮箱帐号
  • 授权码
  • 发件人名称,可选

3. 批量导入导出

支持以下格式,每行一条:

渠道名----帐号----授权码

例如:

QQ邮箱----demo@qq.com----abcd1234
163邮箱----demo@163.com----efgh5678

说明:

  • 导入时按“渠道名”匹配已有渠道
  • 如果渠道不存在,会直接报错
  • 如果同一渠道下邮箱已存在,则更新授权码
  • 导出会导出全部帐号,格式同上

4. 收信

点击左侧邮箱帐号后会:

  • 复制邮箱号到剪贴板
  • 立即触发收信
  • 拉取全部可读文件夹中的最近邮件
  • 在中间栏展示邮件列表
  • 在右侧显示邮件详情

为了避免 IMAP 全量拉取过慢,系统使用“两阶段策略”:

  • 先同步邮件列表与头信息
  • 打开某封邮件时再按需拉取正文详情

5. 发信

点击左上角“写邮件”按钮,选择当前邮箱帐号后即可发信。

API 文档

健康检查登录状态登录接口 外,其余 API 在启用鉴权时都需要先登录,或提供有效的 API Token。

API Token 支持两种传法:

Authorization: Bearer <API_TOKEN>

或:

X-API-Token: <API_TOKEN>

健康检查

curl http://localhost:3000/api/health

登录状态

curl http://localhost:3000/api/auth/status

返回结果中会包含 tokenEnabled 字段,用于表示是否启用了 API Token。

登录

curl -X POST http://localhost:3000/api/auth/login \
  -H 'Content-Type: application/json' \
  -d '{
    "password": "your-strong-password"
  }'

退出登录

curl -X POST http://localhost:3000/api/auth/logout

查询渠道

curl http://localhost:3000/api/channels

使用 Bearer Token

curl http://localhost:3000/api/channels \
  -H 'Authorization: Bearer your-strong-api-token'

使用 X-API-Token

curl http://localhost:3000/api/channels \
  -H 'X-API-Token: your-strong-api-token'

新增渠道

curl -X POST http://localhost:3000/api/channels \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "企业邮箱",
    "code": "corp",
    "imap_host": "imap.example.com",
    "imap_port": 993,
    "imap_secure": true,
    "smtp_host": "smtp.example.com",
    "smtp_port": 465,
    "smtp_secure": true
  }'

查询帐号列表

curl http://localhost:3000/api/accounts

新增邮箱帐号

curl -X POST http://localhost:3000/api/accounts \
  -H 'Content-Type: application/json' \
  -d '{
    "channel_id": 1,
    "email": "your-account@qq.com",
    "auth_code": "邮箱授权码",
    "display_name": "业务邮箱"
  }'

删除邮箱帐号

curl -X DELETE http://localhost:3000/api/accounts/1

批量导出帐号

curl http://localhost:3000/api/accounts/export

批量导入帐号

curl -X POST http://localhost:3000/api/accounts/import \
  -H 'Content-Type: application/json' \
  -d '{
    "content": "QQ邮箱----demo@qq.com----abcd1234\n163邮箱----demo@163.com----efgh5678"
  }'

发送邮件

curl -X POST http://localhost:3000/api/send \
  -H 'Authorization: Bearer your-strong-api-token' \
  -H 'Content-Type: application/json' \
  -d '{
    "accountId": 1,
    "to": "target@example.com",
    "subject": "测试邮件",
    "text": "这是一封来自 API 的测试邮件"
  }'

获取邮件列表

首次建议带 refresh=true,从远程 IMAP 同步最新邮件。

curl "http://localhost:3000/api/messages?accountId=1&limit=20&refresh=true" \
  -H 'Authorization: Bearer your-strong-api-token'

获取最新一封邮件

curl "http://localhost:3000/api/messages/latest?accountId=1&refresh=true" \
  -H 'Authorization: Bearer your-strong-api-token'

获取单封邮件详情

curl "http://localhost:3000/api/accounts/1/messages/INBOX%3A123?refresh=true" \
  -H 'Authorization: Bearer your-strong-api-token'

说明:uid 需要使用 URL 编码。

数据说明

  • channels:邮箱渠道配置
  • accounts:邮箱帐号和授权码
  • mail_cache:同步后的邮件缓存

默认本地数据库文件为:

./mail.db

如果通过 Docker 运行,则默认为:

/data/mail.db

部署建议

  • 生产环境建议使用反向代理,如 Nginx 或 Traefik
  • 建议通过 HTTPS 暴露服务
  • 当前授权码存储在 SQLite 中,生产环境建议改为加密存储
  • 建议增加访问控制与登录认证,避免未授权访问

当前实现边界

  • 当前未实现附件上传与下载
  • 当前未实现用户登录、权限和多租户隔离
  • 当前邮件缓存为本地 SQLite不适合超大规模并发
  • 当前 HTML 邮件正文做了基础清理,但不是完整沙箱渲染

后续建议

如果准备继续往生产方向演进,建议优先补以下能力:

  1. 用户登录与权限管理
  2. 授权码加密存储
  3. 附件收发
  4. 邮件标签、已读未读、分页
  5. 定时自动拉取邮件
  6. 发信模板和批量发信
  7. 更完整的 HTML 邮件安全隔离策略