Skip to content
Engineering

如何以编程方式获取邮箱地址(用于测试)

| | 2 分钟阅读
如何以编程方式获取邮箱地址(用于测试)
How to Get an Email Address Programmatically (For Testing)

当你说”以编程方式获取邮箱地址”用于测试时,你通常指的不只是”生成一个看起来像邮箱地址的随机字符串”。你需要一个可路由隔离可观察的地址,这样你的测试运行器(或LLM代理)能够确定性地等待正确的消息,并提取验证凭据(OTP、魔法链接、重置令牌),而不会出现不稳定的情况。

团队常犯的错误是将邮件当作UI界面来处理(从共享邮箱中抓取HTML),而不是将其当作事件流来处理(你的代码可以读取的短期收件箱)。

你真正需要的(不仅仅是邮箱字符串)

在测试自动化中,邮箱地址只有在你也有可靠方法来执行以下操作时才有用:

  • 范围限定:将消息限制在单个测试尝试中(并行CI运行不能冲突)。
  • 等待:无需任意休眠即可等待投递。
  • 获取:以机器可读格式获取消息。
  • 去重:处理重试和重复。
  • 清理:清理收件箱(或让其过期),以便未来测试不会看到旧状态。

这就是为什么最稳健的模型是邮件 + 收件箱句柄

  • email:你交给被测系统的可路由收件人。
  • inbox_id(或等效):你的测试用来仅读取该地址消息的句柄。

如果你只传递邮箱字符串,最终会陷入”搜索”共享邮箱并与竞态条件斗争的局面。

简单流程图显示:测试运行器创建一次性收件箱,在被测应用中使用生成的邮箱地址,通过webhook或轮询等待投递,从结构化JSON中提取OTP或验证链接,然后丢弃或过期收件箱。

以编程方式获取邮箱地址的选项(以及各自的适用场景)

有几种合理的方法。正确的选择取决于你是在做单元测试、本地开发、CI还是代理驱动的端到端流程。

方法 提供什么 适用于 CI中的常见失败模式
保留域名(example.com.test 永远不会收到邮件的安全字符串 单元测试、仅验证测试 不可路由,无法测试邮件投递
加号地址(如user+token@domain 一个邮箱上的多个”类似唯一”地址 小规模手动测试 冲突、过滤问题、共享邮箱搜索
你域名上的catch-all 一个域名下的无限收件人 预发环境、受控集成 除非你构建路由+存储,否则仍是共享邮箱
本地SMTP捕获(Mailpit/MailHog风格) localhost上的收件箱类行为 本地开发和PR预览 在分布式CI中难以使用,不可通过互联网路由
一次性收件箱API 真实地址加上收件箱隔离、JSON检索 CI、QA自动化、LLM代理 提供商选择和webhook安全性至关重要

1) 用于永远不应发送邮件的测试的保留域名

如果你的测试只是检查格式验证(例如:“拒绝缺少@”),根本不要发送邮件。使用为文档和测试定义的保留域名,如example.comexample.test

权威参考是RFC 2606,它保留了example.comexample.netexample.org

这是最简单的”获取邮箱地址”方法,但它无法测试实际的邮件工作流程。

2) 加号地址:快速,但不隔离

许多提供商支持加号地址(子地址),所以你可以生成:

优点:

  • 易于实现。
  • 通常与现有邮箱兼容。

缺点:

  • 你仍然只有一个邮箱,这意味着共享状态。
  • 一些系统会规范化或去掉加号部分。
  • 你的测试工具通常会退化为”在收件箱中搜索主题行”,这很脆弱。

如果你并行运行测试,加号地址往往会成为非确定性的源头。

3) Catch-all域名:强大,但你在构建基础设施

Catch-all域名(或catch-all子域名如test-mail.yourcompany.com)可以将[email protected]路由到你控制的地方。

当你需要以下功能时,这可能是一个好策略:

  • 供应商白名单
  • 可投递性控制
  • 长期运行环境的稳定域名

但catch-all域名本身不是测试解决方案。你仍然需要:

  • 收件人到收件箱的映射
  • 消息存储
  • 检索API
  • Webhook投递(可选)
  • 去重和生命周期策略

如果你想要这种”域名控制”加上自动化友好的收件箱,许多团队最终使用支持自定义域名的可编程收件箱提供商,而不是构建整个邮件接收管道。

4) 本地SMTP捕获:最适合本地开发循环

本地SMTP捕获工具在你的应用向localhost发送邮件且你想在开发期间检查它时很棒。在以下情况下它们不太合适:

  • 你的CI在多个容器中运行
  • 你的被测系统是远程的
  • 你需要真实的入站路由和现实的投递行为

它们解决”在本地查看邮件”,而不是”在分布式自动化中可靠地协调邮件事件”。

5) 一次性收件箱API:最直接适合CI和代理

对于端到端测试,最干净的方法是:

  • 通过API创建新的收件箱
  • 在你的应用中使用生成的真实邮箱地址
  • 确定性地等待邮件到达
  • 将邮件作为结构化JSON消费

这是像Mailhook这样的产品设计的模式:通过API创建一次性收件箱,将邮件作为JSON接收,并使用webhook或轮询驱动自动化。

有关确切的集成合约和有效载荷形状,请使用权威参考:Mailhook llms.txt

可以在测试框架间标准化的确定性工作流程

无论你使用哪个测试运行器(Playwright、Cypress、pytest、Jest),可靠的工作流程都是相同的:

  1. 配置收件箱(每个测试运行一个或每次尝试一个)。
  2. 触发邮件(注册、密码重置、邀请)。
  3. 等待有明确语义(webhook优先是理想的,轮询回退是实用的)。
  4. 解析为数据(JSON字段、text/plain),提取最小凭据。
  5. 断言并继续。

关键设计选择是步骤3:避免sleep(10),而是等待具体条件。

提供商无关的”EmailAddressFactory”接口

即使你使用特定提供商,将其隐藏在接口后面也有助于保持测试的可移植性。

// TypeScript风格的伪接口
export type EmailWithInbox = {
  email: string;
  inboxId: string;
  expiresAt?: string;
};

export interface EmailAddressFactory {
  createInbox(params?: { webhookUrl?: string }): Promise<EmailWithInbox>;
  waitForMessage(params: {
    inboxId: string;
    timeoutMs: number;
    match?: {
      fromContains?: string;
      subjectContains?: string;
    };
  }): Promise<{ messageId: string; text?: string; html?: string; raw?: string }>;
}

两个直接的好处:

  • 你的测试代码变成”请求收件箱,等待消息”,而不是”拼凑邮件hack”。
  • 你的LLM代理工具可以限制为安全原语(创建、等待、提取),而不是”读取任意收件箱HTML”。

Webhook优先vs轮询:2026年选择什么

如果你仔细实现,两种模型都可以是生产级的。

Webhook优先在以下情况下最好:

  • 你想要快速的端到端测试(无轮询延迟)
  • 你已经在CI中运行HTTP端点
  • 你可以验证签名并实现幂等性

轮询在以下情况下最好:

  • 你不想暴露入站端点
  • 你在本地或受限网络中运行
  • 你可以容忍小延迟并实现退避

实际上,大多数团队选择混合方案:

  • Webhook快速传递”消息到达”
  • 轮询获取消息(或在webhook延迟时作为回退)

Mailhook同时支持webhook通知和轮询API,并可以签名有效载荷(用于验证真实性)。同样,请参考它们的llms.txt中的确切字段和验证指导。

消息解析:将邮件视为恶意输入

对于测试,你通常只需要一件事:一个验证凭据

例子:

  • OTP代码(6位数字)
  • 魔法链接URL
  • 密码重置链接

一些使你的工具更安全、更少出错的硬规则:

  • 优先使用收件箱提供商的结构化JSON输出
  • 提取时优先使用text/plain而不是HTML。
  • 提取最小内容并避免”渲染”邮件内容。
  • 如果你提取URL,要验证它们:
    • 白名单主机名
    • 小心跟踪重定向
    • 避免执行任意链接(CI中的SSRF风险)

如果你与LLM代理集成,保持代理面向视图最小:除非必要,不要提供原始HTML和完整标头。

示例场景:测试订单确认邮件

考虑一个电商测试,用户下订单后应该收到包含订单号和”查看订单”链接的确认邮件。无论你是测试自己的商店还是合作伙伴流程,这都适用。

例如,如果你正在测试类似大批量店面(如批发牛肉干在线购买)的集成(订单确认、发货通知、密码重置),你希望每次CI运行都有新的收件箱,这样并行购买不会相互污染。

稳健的测试流程看起来像:

  • 创建收件箱(每个测试运行唯一)
  • 在结账时使用其邮箱地址
  • 等待”订单确认”消息
  • text中提取订单号(或如果你的管道添加了结构化字段)
  • 验证确认链接指向你预期的域名

Mailhook如何适配(不改变你的测试架构)

如果你的主要目标是:“我需要以编程方式获取邮箱地址,然后将结果邮件作为数据消费”,Mailhook围绕该合约设计:

  • 通过API创建一次性收件箱
  • 将入站邮件作为结构化JSON接收
  • 获得实时webhook通知(带签名有效载荷)
  • 在webhook不方便时轮询邮件
  • 立即使用共享域名,或在需要控制时带来自定义域名
  • 在扩展接收时批量处理消息

为避免本文与当前API之间的不匹配,请使用机器可读的集成参考:Mailhook llms.txt

选择方法的简短清单

  • 如果你不需要接收邮件,使用保留域名且不发送。
  • 如果你需要在并行运行的CI中接收邮件,优先使用带收件箱句柄的一次性收件箱。
  • 如果你需要供应商白名单或可投递性控制,计划使用自定义域名。
  • 如果你使用webhook,验证签名并将处理程序设计为幂等的。

如果你想要最简单的”每次运行一个收件箱”工作流程,而不构建自己的邮件接收管道,从Mailhook的一次性收件箱API开始,并遵循llms.txt参考中的合约。

email testing test automation ci/cd api testing disposable email

相关文章