MailHog:遗留邮件捕获服务如何安全退出
还能启动,不代表可以继续扩建
MailHog 的官方仓库仍可访问,正式发布列表也仍将 v1.0.1 标为最新版本,但正式发布长期停留在这条旧版本线。官方 README 说明它能接收 SMTP、通过 Web UI/API 查看邮件,并支持内存、maildir 与 MongoDB 存储;这些能力解释了为什么许多历史测试仍然能跑,却不能证明项目仍有稳定的安全修复或多架构镜像维护承诺。版本与能力应分别从 官方发布页 和 官方仓库 核对。
因此,MailHog 的合理定位是“有 owner、有退出日期的兼容依赖”。新项目直接选择 Mailpit;旧项目若暂时迁不动,要把使用它的原因写清楚:测试是否依赖 /api/v2/messages,是否使用 maildir/MongoDB,是否调用 release-to-SMTP,或者 CI 镜像是否只能在 linux/amd64 下运行。
锁定一套最小兼容环境
services:
mailhog:
image: mailhog/mailhog:v1.0.1
platform: linux/amd64
ports:
- "127.0.0.1:1025:1025"
- "127.0.0.1:8025:8025"
environment:
MH_STORAGE: memory端口只绑定回环地址。Web UI 与 API 没有用户级邮箱隔离,捕获到的验证码、重置链接、收件人和正文都是敏感测试数据;共享环境应在反向代理层增加身份验证,并禁止真实客户数据进入测试邮件。MH_AUTH_FILE 能保护 UI/API,但不等于 SMTP 入口已经受控。
启动后先发一封带唯一关联值的假数据邮件,再用 API 证明它来自本次运行:
curl -fsS http://127.0.0.1:8025/api/v2/messages | jq '.total'
curl -fsS http://127.0.0.1:8025/api/v1/messages | jq '.[] | .Content.Headers.Subject'UI 中“看见一封邮件”不能替代关联值断言。并发 CI 必须每个 job 使用独立 Compose project,或在测试前后按可证明的范围清理消息。
存储选择决定退出成本
内存存储适合一次性测试,进程退出即清空。MH_STORAGE=maildir 还要管理 MH_MAILDIR_PATH;MH_STORAGE=mongodb 则引入 MH_MONGO_URI、数据库、collection、备份和凭证。MailHog 没有 Mailpit 的数量与年龄保留组合,持久化实例需要外部清理,否则敏感邮件与磁盘占用会持续增长。
不要把 MailHog 数据目录挂给 Mailpit。两者的存储格式、API 响应和认证配置都不同,复制 volume 既不是迁移,也不是回滚。真正需要保留的通常不是历史测试邮件,而是测试代码对 SMTP 和查询 API 的行为合同。
迁移只保住行为合同
先列出五类依赖:SMTP host/port、API 查询、删除语义、认证、持久化。SMTP 地址通常可以直接切换;/api/v2/messages 要改成 Mailpit /api/v1/messages 或 /api/v1/search;MH_STORAGE 要改为 MP_DATABASE 和保留策略;Basic Auth 文件、Chaos 行为以及 release-to-SMTP 若被使用,都要单独重测。
迁移阶段让两套服务使用不同端口和不同存储,以同一封假数据邮件执行正向查询、错误 SMTP、删除和重启实验。通过后切换应用配置并保留旧 Compose 作为短期回退包。回退只切服务地址和 API 适配层,不复制数据库文件。
停止条件不是“新页面能打开”,而是所有测试都不再请求 MailHog API,CI 不再拉取旧镜像,旧 maildir/MongoDB 已按数据规则销毁,反向代理、凭证和端口均撤销。到这一步,MailHog 才真正退出,而不是从文档里消失后继续在流水线里运行。
为什么保留独立文章
MailHog 与 Mailpit 是两个独立产品,不应再共享一篇交替教程。这篇文章只服务仍有 MailHog 依赖的团队,明确旧运行时如何被约束和移除;Mailpit 的正常学习路径由自己的主文章承担。这样既不抹掉迁移事实,也不会让新读者误以为两者是同一个工具的两种模式。
