为什么要在业务里单独做一次邮箱检测
用户准备、活动报名、邮件订阅这类流程中,邮箱是账号恢复、通知触达和身份确认的重要载体。一个看似合法的邮箱地址,可能在格式上通过校验,但实际域不存在 MX 记录,或者来自临时邮箱域名。若不在入口处拦截,后续会带来大量无法送达的邮件、虚假账号和风控维护复杂度。
邮箱地址检测接口把多个维度的判断合并成一次 HTTP 请求,返回统一的评分和原因清单,适合嵌入到准备表单提交、批量名单清洗、KYC 辅助核验等环节。本文记录这个接口的接入参数、返回结构和工程落地时的注意事项,供后端开发同学参考。
接口能力边界
在写代码之前,先明确这个接口能做什么、不能做什么,避免误用。
一次请求完成 6 项检测:
- RFC 5322 格式校验:判断邮箱整体结构是否符合规范。
- 临时/一次性邮箱检测:基于 72,345 条开源域名库、3 个数据源合并去重后的结果进行比对。
- MX 记录验证:通过 AliDNS DoH 查询域名 MX 记录,不依赖服务器本地的 getmxrr 函数,结果更稳定。
- 拼写纠正:对常见域名拼写错误给出建议,例如
gmial.com提示为gmail.com。 - 服务商识别:识别 QQ 邮箱、Gmail、网易、Outlook 等 40+ 主流邮箱服务商。
- 综合风险评分:输出 0-100 的风险分数,并附带详细原因清单。
接口的 QPS 配额为 10 / s,邮箱地址最长支持 254 字符(RFC 上限)。需要说明的是,接口返回的是单一时间点的检测结果,不保证域名后续新增或删除 MX 记录会实时反映,域名库的更新频率以文档为准。
请求参数与鉴权
Query 参数
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
email | string | 是 | 要检测的邮箱地址,最长 254 字符 |
Header 参数
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
X-API-Key | string | 否 | API Key,不传时走匿名额度 |
接口为 GET 请求,地址为https://v1.apizero.cn/api/email-check。匿名额度不要求携带X-API-Key,但在高并发或生产环境建议申请独立的 API Key 使用,具体申请方式以文档为准。
curl 接入示例
先通过 curl 验证接口连通性,替换$APIZERO_API_KEY为你的实际 Key,将<email>替换为目标邮箱:
curl -sS \ -X GET \ -H "X-API-Key: $APIZERO_API_KEY" \ "https://v1.apizero.cn/api/email-check?email=<email>"如果不带 Key,直接去掉 Header 即可:
curl -sS \ "https://v1.apizero.cn/api/email-check?email=test@gmial.com"上述命令返回 JSON 数组,其中code为 0 时表示请求成功。注意响应是一个数组结构,即使只返回一个元素,也需要按数组解析。
Python 代码接入示例
在实际业务中,通常不在命令行里调用,而是封装成一个服务函数。以下是一个基于requests库的接入示例:
import requests API_ENDPOINT = "https://v1.apizero.cn/api/email-check" API_KEY = "your-api-key-here" # 不传则走匿名额度 def check_email(email: str, timeout: float = 5.0) -> dict: headers = {} if API_KEY: headers["X-API-Key"] = API_KEY params = {"email": email} resp = requests.get(API_ENDPOINT, params=params, headers=headers, timeout=timeout) resp.raise_for_status() # 接口返回 JSON 数组,取第一个元素 body = resp.json() if not isinstance(body, list) or len(body) == 0: raise ValueError("unexpected response format") item = body[0] if item.get("status") != "200" or item.get("code") != 0: raise RuntimeError("api error: {}".format(item)) return item["data"] if __name__ == "__main__": result = check_email("test@gmial.com") print("risk_score:", result["risk_score"]) print("risk_level:", result["risk_level"]) print("reasons:") for reason in result["reasons"]: print(" -", reason)这段代码做了三件必要的事:设置超时、通过raise_for_status()暴露 HTTP 层错误、校验响应结构后再取数据。生产环境中建议把API_KEY放到环境变量或密钥管理服务中,不要硬编码在代码仓库里。
返回字段解读
以素材中的test@gmial.com为例,成功响应中data部分包含以下关键字段:
| 字段名 | 类型 | 说明 |
|---|---|---|
email | string | 原始邮箱地址 |
input | string | 用户输入值 |
local | string | 邮箱地址的本地部分 |
domain | string | 邮箱地址的域名部分 |
valid_format | bool | 是否符合 RFC 5322 格式 |
has_mx | bool | 域名是否存在 MX 记录 |
mx_records | array | MX 记录列表,无记录时为空数组 |
is_disposable | bool | 是否属于临时/一次性邮箱域名 |
disposable_match | string/null | 命中的临时邮箱域名记录来源 |
provider | string/null | 识别的邮箱服务商名称 |
is_trusted | bool | 是否属于可信域名 |
spelling_suggestion | string/null | 拼写纠正建议 |
risk_score | int | 综合风险评分,0-100 |
risk_level | string | 风险等级,例如invalid |
reasons | array[string] | 风险原因清单 |
data 外层还有code、msg、request_id三个字段。request_id在排查问题时非常有用,建议在日志中记录。
在示例中,risk_score为 5,risk_level为invalid,原因是域名无 MX 记录、域名疑似拼写错误、本地部分含测试/系统类关键词。这说明风险评分不是只看单一维度,而是综合了格式、域名可接收性、临时邮箱库和历史经验等多方面信息。
几个容易误解的字段
is_disposable: false并不代表邮箱一定安全,还需要结合has_mx和risk_score综合判断。provider: null表示接口未能识别域名属于哪家服务商,可能是小众域名或拼写错误域名。spelling_suggestion只在识别出疑似拼写错误时返回,正常域名下为null。
常见错误与排查思路
接入过程中遇到问题,按照以下层次排查效率更高。
1. HTTP 层异常
400 Bad Request:email参数缺失或超过 254 字符,检查 URL 编码是否正确。401 Unauthorized:X-API-Key无效或已过期,确认 Key 是否复制完整。429 Too Many Requests:请求频率超过 10 QPS 配额,需要降速或联系调整配额。
2. 响应结构与状态码不一致
接口返回 HTTP 200 时,业务层面的code字段仍然可能表示失败。不能只判断 HTTP 状态码,还要检查code和status。建议在代码中统一断言:item["status"] == "200" and item["code"] == 0。
3. DNS 与 MX 查询的时延波动
MX 记录验证依赖 DNS 查询,极端情况下可能使整体接口耗时拉长。客户端设置 5 秒超时是一个相对稳妥的起点,如果业务链路对耗时敏感,可以加入缓存策略(见下文)。
4. 邮箱地址的特殊字符
部分邮箱地址包含+、-、_等字符,例如user+tag@example.com。在拼接 URL 时,务必使用params字典或urlencode处理,不要手动拼接字符串,避免+被解析为空格。
工程化注意事项
超时与重试
网络请求必须设置超时,并按业务容忍度配置重试。建议采用指数退避策略:第一次失败后等待 1 秒、第二次 2 秒、第三次 4 秒,最多重试 2 次。对于用户准备场景,可以在前端先做一次本地格式校验,再把完整检测放到后端异步执行,避免同步阻塞表单提交。
缓存设计
同一邮箱在短时间内被重复检测的场景很常见。可以按邮箱地址做本地缓存,TTL 设为 10-30 分钟,降低接口调用量。需要注意,MX 记录和临时邮箱域名库会变化,缓存时间不宜过长。如果业务对准确性要求极高,可以不缓存risk_score,只缓存valid_format等几乎不会变化的字段。
批量场景的速率控制
接口 QPS 为 10 / s,批量清洗邮件列表时不能一次性并发发出大量请求。建议在本地做令牌桶限流,控制请求速率在 8 QPS 左右,留出余量。同时记录每个request_id,方便对账。
日志与监控
至少记录以下信息:
- 调用时间、目标邮箱、接口耗时
- HTTP 状态码、业务 code、request_id
- 返回的 risk_score 和 risk_level
- 异常类型和重试次数
这些数据接入监控后,可以及时发现接口调用异常或业务异常波动,例如某个时间段risk_score平均值突然升高,可能意味着临时邮箱域名库更新或被攻击者利用。
不要做的事
- 不要把接口返回的
risk_score直接作为唯一决策依据,建议结合业务规则(如黑名单、准备频次)综合判断。 - 不要用
reasons数组的中文文案直接展示给终端用户,这些内容更适合在后台风控日志里查看。 - 不要忽略匿名额度的限制,生产环境请使用正式 API Key。
小结
邮箱地址检测接口把格式校验、临时邮箱识别、MX 验证、拼写纠正、服务商识别和风险评分打包成一个简单 GET 请求,降低了风控逻辑的重复开发维护复杂度。接入时重点关注响应数组结构、业务码判断、超时重试和速率限制,即可稳定嵌入到准备、营销、KYC 等场景中。
参考文档
- 接口文档:https://apizero.cn/aidocs/email-check
- 原始文档:https://apizero.cn/aidocs/email-check/raw.md