一个用于批量管理 Outlook、Gmail POP、通用 POP/IMAP、Proton 与转发邮箱映射的全栈 Web 应用。
当前主后端为 Go,前端为 React,默认使用 SQLite,也支持 PostgreSQL。
- Outlook 账户管理、Graph API / IMAP 收信与令牌刷新
- POP 账户管理、POP3/POP3S 收信;其中 Gmail 模式支持别名识别
- 通用 IMAP 与 Proton 邮箱管理、收信、标签和导入导出
- 转发邮箱管理:保存
转发邮箱 -> 目标邮箱地址映射,目标邮箱从系统内已有账户自动匹配 - 标签、代理、API Token、备份恢复、仪表盘统计
- 内嵌前端静态资源,单二进制即可提供完整 Web 服务
账号凭据管理与邮件读取已经拆开。账号管理数据保存在独立的 managed_accounts 表,邮件模块继续使用自己的 accounts 表。两者在同一个 Go 服务内由同步服务直接通过数据库事务同步,不需要两个项目之间互调接口。provider 适配器当前实现 Outlook/Microsoft OAuth,后续可以增加其他邮箱类型。
Outlook 导入导出与 OutlookManage、Outlook-Oauth-GetToken 使用相同格式:
邮箱----密码----client_id----refresh_token
常用接口:
POST /api/managed-accounts/import # 文本导入,同邮箱可选跳过/覆盖
POST /api/managed-accounts/upsert # 单账号 JSON 新增或覆盖
POST /api/managed-accounts/sync # 内部批量同步到邮件账号
POST /api/managed-accounts/{id}/sync # 内部同步单个账号
POST /api/managed-accounts/refresh # 指定 ids 或批量刷新
POST /api/managed-accounts/{id}/refresh # 单账号刷新
POST /api/managed-accounts/export # 四段兼容格式导出
POST /api/managed-accounts/status # 批量封禁或解除封禁
POST /api/managed-accounts/remove-mailbox # 只删除邮件投影,保留管理账号
POST /api/managed-accounts/recover-abuse # 批量尝试 ABUSE 恢复
导入示例:
{
"provider": "outlook",
"text": "user@outlook.com----password----client_id----refresh_token",
"mode": "overwrite"
}导入时可选择同邮箱“跳过”或“覆盖”;导入只更新账号管理源,不直接改邮件账号。之后在页面点击“同步到邮件”,服务会内部批量创建或覆盖邮件所需账号信息。服务每 6 小时扫描一次邮件账号的待刷新 token,并保存微软返回的新 refresh_token;对已经关联的管理账号会同时回写新 token,避免下次同步回退到旧值。invalid_grant、refresh token 过期或被撤销会标记为 reauthorization_required,需要重新授权后导入覆盖。
封禁账号始终保留在账号管理中,并从普通同步、自动刷新和批量收信中排除。Microsoft 返回 service abuse / abuse mode 时会自动标记为 banned、ban_type=abuse;锁定、禁用、删除账号会分别记录对应封禁类型。页面上的“从邮箱移除”只删除邮件账号投影(以及数据库级联的缓存/标签关联),不会删除管理源。
ABUSE 解封需要单独配置恢复 Runner。不配置时接口返回 enabled=false 和 status=disabled,不会把“已发起”当作成功。Runner 从标准输入接收账号 JSON,并必须从标准输出返回包含新 refresh token 的成功 JSON:
{"success":true,"reason_code":"recovered","reason":"","refresh_token":"new-refresh-token"}配置 ABUSE_RECOVERY_COMMAND(可执行文件及空格分隔参数)与 ABUSE_RECOVERY_TIMEOUT(秒,默认 300)。恢复成功只更新管理源并清除封禁,之后由操作者决定是否重新同步到邮件模块。
转发邮箱用于管理“外部投递地址”,但真正收件仍由系统内已有邮箱完成。
- 新增或导入时只需要填写
email(转发邮箱地址)和target_email(目标邮箱地址)。 - 系统会按
target_email在 Outlook、Gmail POP、通用 POP、通用 IMAP、Proton 账户中查找目标邮箱。 - 如果目标邮箱不在系统内,记录仍会被保存或导入,但会显示为“目标异常 / 不可收件”。
- 支持批量修改转发目标邮箱,选中多条转发邮箱后统一输入新的
target_email即可。 - 自动化 API 可使用
provider=forward获取和读取转发邮箱,读取邮件时系统会自动切到目标邮箱。
常用导入格式:
forward@example.com----target@example.com----备注
对应字段顺序:
email----target_email----remark
| 层级 | 技术 |
|---|---|
| 后端 | Go 1.25 + Chi + sqlx |
| 数据库 | SQLite / PostgreSQL |
| 前端 | React 19 + Vite 6 + Tailwind CSS 3 + Zustand 5 |
| 构建部署 | Docker / Render |
email-manager/
├── server-go/ # Go 后端
│ ├── cmd/server/ # 程序入口
│ └── internal/ # 路由、模型、服务、嵌入静态资源
├── web/ # React 前端
├── data/ # 默认数据目录(Docker Compose 使用)
├── Dockerfile # Go 版生产镜像
├── docker-compose.yml # 本地容器部署
└── render.yaml # Render Blueprint
- Go >= 1.25
- Node.js >= 20
- npm >= 10
npm install
npm run setupcp .env.example .env| 变量 | 默认值 | 说明 |
|---|---|---|
PORT |
3000 |
服务端口 |
LOG_LEVEL |
info |
日志级别 |
DB_TYPE |
sqlite |
数据库类型,支持 sqlite / postgres |
DB_PATH |
./data/email-manager.db |
SQLite 文件路径 |
DATABASE_URL |
(空) | PostgreSQL 连接串,仅 DB_TYPE=postgres 时使用;Supabase、Neon、Render PostgreSQL、CockroachDB Cloud 这类 PostgreSQL wire protocol 服务也使用该模式 |
ADMIN_PASSWORD |
(空) | 后台登录密码,留空则不启用 |
PROTON_MASTER_KEY |
内置默认值 | Proton 登录密码和邮箱解锁密码的加密主密钥;生产环境建议显式设置 |
ABUSE_RECOVERY_COMMAND |
(空) | 可选 ABUSE 恢复 Runner;未配置时恢复接口返回 disabled |
ABUSE_RECOVERY_TIMEOUT |
300 |
ABUSE Runner 超时秒数 |
npm run dev- 前端:
http://localhost:5173 - 后端:
http://localhost:3000
npm run build
npm startGo 服务会托管嵌入后的前端静态资源,直接访问 http://localhost:3000 即可。
docker compose up -d --build默认数据会写入根目录 data/,容器内路径为 /app/data。
仓库已提供根目录 render.yaml,默认使用 Render 原生 Go 构建 Go 版服务,实例计划为 free,数据库配置保持为 PostgreSQL。使用 CockroachDB Cloud、Supabase、Neon 等 PostgreSQL wire protocol 服务时,仍设置 DB_TYPE=postgres,并把 DATABASE_URL 配置为对应服务提供的连接串。
server-go/README.md保留了 Go 后端目录内的补充说明。server-go-plan/contract.md记录了迁移期的行为约束文档。