Notion Blog
技术分享1 分钟阅读

mail.cx临时邮箱:测试接入说明与 Python示例

在需要邮箱验证的测试场景中,你是否为以下问题烦恼?

手工注册新账号,需要反复查收、填写验证码,效率低下。

测试账号与个人/工作邮箱绑定,测试邮件污染收件箱。

自动化测试中,邮箱的注册、收信、解析环节不稳定,难以断言。

临时邮箱服务是解决这些痛点的绝佳工具。 本文将以 Mail.cx为例,为你梳理从手动操作到接口集成的完整使用指南,助你显著提升测试效率。

一、核心价值:为什么测试要用临时邮箱?

在注册、验证码、找回密码、通知触达等场景中,临时邮箱能帮助测试同学:

快速造号,降低手工成本:瞬间生成专属邮箱,无需准备或寻找真实邮箱。

隔离测试数据,避免污染:测试邮件与真实邮箱完全隔离,收件箱清爽可控。

稳定自动化流程:为自动化测试提供稳定的「收件 → 解析 → 断言」能力,实现端到端验证。

二、快速上手:页面使用(手动测试)

对于手工测试或快速验证,网页版是最直接的方式。

访问地址:https://mail.cx

创建邮箱:

在输入框中,可以自定义邮箱前缀(如 my_test_user),或直接点击“随机生成”。

选择可用的域名(如 @mail.cx)。

设置密码,点击“创建账户”。

查看邮件:

创建成功后,页面即转为收件箱。系统发送的欢迎邮件会即刻到达。

邮件列表会直接展示发件人、主题和部分内容预览。

查看详情:点击任意邮件,即可查看完整内容,包括发件人、收件人、主题、HTML/纯文本正文等。

三、集成指南:API 使用(自动化测试)

基础地址:https://api.mail.cx。官方参考:Mail.cx API

[table]

推荐心智模型:先域名 → 拼一个不撞车的地址 → 建号 → 拿 token → 轮询收件 → 用 id 拉详情。

2. 响应结构:和文档不一致时怎么解析

线上返回与 OpenAPI 文档里的 hydra:member 不一定一致。下面按「实际常见字段 → 兜底」来写解析逻辑即可。

2.1 GET /api/domains

常见domains: [{ "id", "domain", ... }]
兜底hydra:member
建议:优先读 domains,没有再读 hydra:member

2.2 GET /api/messages

常见messages: [],并可能带 page
兜底hydra:member / items / data
建议:按固定顺序找「第一个列表字段」作为邮件数组

2.3 POST /api/accounts

成功时响应里可能直接带 token,语义与 /api/token 一致。
示例脚本里仍调用 /api/token,是为了:流程清晰、以及后续「已有账号只换 token」时可直接复用。

3. Python 示例

依赖:pip install requests

import time
import requests

BASE_URL = "https://api.mail.cx"
TIMEOUT = 10


def get_domains() -> dict:
    resp = requests.get(f"{BASE_URL}/api/domains", timeout=TIMEOUT)
    return {"status": resp.status_code, "body": resp.json()}


def _domain_entries_from_body(body: dict) -> list:
    """兼容实际返回 domains[] 与文档中的 hydra:member 两种结构。"""
    if not isinstance(body, dict):
        return []
    if "domains" in body and isinstance(body["domains"], list):
        return body["domains"]
    member = body.get("hydra:member")
    if isinstance(member, list):
        return member
    return []


def _message_entries_from_body(body: dict) -> list:
    """收件列表可能为 hydra:member 或 messages 等字段。"""
    if not isinstance(body, dict):
        return []
    for key in ("hydra:member", "messages", "items", "data"):
        items = body.get(key)
        if isinstance(items, list):
            return items
    return []


def build_temp_email(domain: str) -> str:
    local = f"qa_temp_{int(time.time())}"
    return f"{local}@{domain}"


def create_temp_account(address: str, password: str) -> dict:
    resp = requests.post(
        f"{BASE_URL}/api/accounts",
        json={"address": address, "password": password},
        timeout=TIMEOUT,
    )
    return {"status": resp.status_code, "body": resp.json()}


def create_token(address: str, password: str) -> dict:
    resp = requests.post(
        f"{BASE_URL}/api/token",
        json={"address": address, "password": password},
        timeout=TIMEOUT,
    )
    return {"status": resp.status_code, "body": resp.json()}


def list_messages(token: str) -> dict:
    headers = {"Authorization": f"Bearer {token}"}
    resp = requests.get(f"{BASE_URL}/api/messages", headers=headers, timeout=TIMEOUT)
    return {"status": resp.status_code, "body": resp.json()}


def get_message(token: str, message_id: str) -> dict:
    headers = {"Authorization": f"Bearer {token}"}
    resp = requests.get(
        f"{BASE_URL}/api/messages/{message_id}",
        headers=headers,
        timeout=TIMEOUT,
    )
    return {"status": resp.status_code, "body": resp.json()}


if __name__ == "__main__":
    password = "Passw0rd!"
    domains_resp = get_domains()
    print("domains:", domains_resp)

    domains_data = domains_resp.get("body", {})
    domains = _domain_entries_from_body(domains_data)
    if not domains:
        raise RuntimeError("未获取到可用域名,无法创建临时邮箱")
    domain = domains[0].get("domain")
    if not domain:
        raise RuntimeError("域名数据结构异常,未找到 domain 字段")

    address = build_temp_email(domain)
    print("temp address:", address)

    account = create_temp_account(address, password)
    print("create account:", account)

    token_resp = create_token(address, password)
    print("create token:", token_resp)
    token = token_resp.get("body", {}).get("token")
    if not token:
        raise RuntimeError("未拿到 token,请检查账号创建/登录流程")

    for i in range(50):
        inbox = list_messages(token)
        print(f"inbox poll #{i + 1}:", inbox)
        items = _message_entries_from_body(inbox.get("body", {}))
        if items:
            first_id = items[0].get("id")
            if first_id:
                detail = get_message(token, first_id)
                print("first message detail:", detail)
            break
        time.sleep(3)

4. 自动化里建议怎么验

用清单比「只盯状态码」更稳:

域名:能解析出至少一个 domain 字符串
建号:HTTP 成功(常见 201),体里有 addressid(有时还带 token
鉴权token 非空;后续请求带 Authorization: Bearer
收件:同时覆盖「暂无邮件」与「已有邮件」;有邮件时用 id 拉详情,断言主题、发件人、正文等关键字段

5. 常见问题速查

[table]

日志里不要完整打印 JWT;对外分享或截图时请打码。临时邮箱仅用于测试场景,勿承载真实隐私。

有关使用上的问题,欢迎您在底部评论区留言,一起交流~

读者评论

评论会同步写入该文在 Notion 中的页面底部(与正文同页,便于管理)。

0/1500

暂无评论,欢迎抢沙发。