Watch-IP

邮箱检查 API 参考

POST/v1/email/validate

检查一个邮箱地址:语法、已知的一次性/临时域名、域名的邮件服务器(MX)、可能的拼写错误和角色地址,并返回附带原因的 accept/review/reject 结论。请发送形如 { "email": "user@example.com" } 的 JSON 请求体。设计为由注册表单自身的 JavaScript 调用,使用与 GET /v1/geo 相同的公开可用、来源锁定密钥模型。如需检查大量地址或在服务器端做出注册决策,请使用本页下文介绍的批量、列表任务和注册检查端点。所有检查均在域名和地址层面进行:不会连接任何邮箱,因此任何结果都不能证明邮箱存在、归谁所有,或邮件能够送达。

身份验证

POST /v1/email/validate 通过 X-Api-Key 请求头接受来源锁定的公开可用密钥——与 GET /v1/geo 相同的密钥类型和允许来源模型。本页的其他所有端点(批量、列表任务、注册检查)接受大量地址或任意 IP,因此需要通过 Authorization: Bearer 提供私密密钥,且只能从您的后端调用;使用公开可用密钥会得到 403。

响应字段

email
您发送的地址,按提交时的原样返回。
domain
小写的域名(国际化域名使用 punycode);当 syntaxValid 为 false 时为 null。
syntaxValid
地址在语法上是否有效。这不是对邮箱是否存在或能否投递的检查。
isDisposable
域名是否匹配已知的一次性/临时邮箱提供商——直接匹配、通过父域名匹配,或通过已知为一次性域名提供服务的邮件服务器匹配。当 syntaxValid 为 false 时始终为 false。
normalizedEmail
去除首尾空白并转为小写、域名使用 punycode 的地址;当 syntaxValid 为 false 时为 null。
canonicalEmail
去除 +标签后的 normalizedEmail(对 Gmail 还会去除点号,并将 googlemail.com 映射为 gmail.com)——保存它可发现同一个人重复注册。当 syntaxValid 为 false 时为 null。
disposableSource
isDisposable 为 true 的原因:list(域名本身在列表中)、parent_domain(父域名在列表中,例如 a.b.mailinator.com)或 mx_host(该域名的邮件服务器为已知的一次性域名提供服务)。当 isDisposable 为 false 时为 null。
isFreeProvider
域名是否为 gmail.com 或 outlook.com 之类的面向个人用户的邮箱提供商。仅供参考——从不改变结论。
isRoleAccount
本地部分是否为 admin@、info@ 或 noreply@ 之类的角色地址。
didYouMean
针对整个地址的可能拼写纠正(john@gmial.com → john@gmail.com),或 null。拥有自身正常工作的邮件服务器的域名不会被“纠正”,除非它与常见提供商仅相差一处编辑。
mx.status
found(存在 MX 记录)、implicit(没有 MX,但有 A/AAAA 记录)、none(两者都没有)、null_mx(域名声明不接收邮件)、no_domain(域名不存在)或 unknown(查询失败或超时)。当 syntaxValid 为 false 时,整个 mx 对象为 null。
mx.host
当 status 为 found 时为优先级值最低的 MX 主机,否则为 null。不能说明单个邮箱是否存在。
verdict
accept、review 或 reject——reasons 中最严重的条件。这是供您自身策略参考的建议,而非最终决定。
reasons
命中的每个条件,按严重程度从高到低排列;当 verdict 为 accept 时为空。参见下文的“结论与原因代码”。

错误

400
请求体格式错误。批量:empty_batch 或 batch_too_large(超过 100 个地址)。注册检查:invalid_ip。列表任务:invalid_body、empty_job 或 job_too_large(超过 100,000 个地址)。无效的邮箱地址永远不会返回 400——而是返回结论为 reject、原因为 invalid_syntax 的结果。
401
API 密钥缺失或无效。
403
POST /v1/email/validate:请求的 Origin/Referer 不在该密钥的允许来源列表中(不会设置 CORS 响应头,因此无论 JSON 内容如何,浏览器都会拦截响应)。私密密钥端点:使用了公开可用密钥。
404
job_not_found——您的账户中没有该 ID 的列表任务。
409
job_not_completed——任务仍在排队或处理中,或已失败;只有任务完成后才能下载结果。
410
job_expired——任务上传的地址和结果已被删除(创建 7 天后)。
413
body_too_large——任务上传的 CSV 超过 10 MB。
415
列表任务的请求体既不是 JSON 也不是 text/csv。
429
每分钟速率限制,或在将超出套餐每月请求上限时返回 monthly_limit_exceeded——如何区分请参阅错误与速率限制。将超出上限的批量请求或列表任务会在任何处理开始前被整体拒绝。
503
job_storage_unavailable——无法存储列表任务。未产生任何费用;请重试。

示例

请求

curl https://api.watch-ip.com/v1/email/validate \
  -H "X-Api-Key: YOUR_PUBLISHABLE_KEY" \
  -H "Content-Type: application/json" \
  -d '{"email": "John.Doe+news@Gmial.com"}'

响应

{
  "email": "John.Doe+news@Gmial.com",
  "domain": "gmial.com",
  "syntaxValid": true,
  "isDisposable": false,
  "normalizedEmail": "john.doe+news@gmial.com",
  "canonicalEmail": "john.doe@gmial.com",
  "disposableSource": null,
  "isFreeProvider": false,
  "isRoleAccount": false,
  "didYouMean": "john.doe+news@gmail.com",
  "mx": {
    "status": "none",
    "host": null
  },
  "verdict": "reject",
  "reasons": [
    "no_mail_server",
    "typo_suspected"
  ]
}

结论与原因代码

每个条件都设定一个最低结论;以最严重者为准,reasons 按严重程度从高到低列出所有条件。是否接受免费邮箱提供商的地址由您决定——它从不改变结论。

invalid_syntax
Reject。地址在语法上无效(长度限制、允许的字符、点号位置、应为真实域名而非 IP 字面量)。带引号的本地部分也会被拒绝——虽然合规,但注册时实际上从不使用。
domain_not_found
Reject。该域名在 DNS 中不存在。
no_mail_server
Reject。该域名声明不接收任何邮件(“null MX”),或既没有 MX 记录也没有 A/AAAA 记录。
disposable_domain
Reject。该域名、其父域名或该域名的邮件服务器匹配已知的一次性/临时邮箱提供商——参见 disposableSource。
typo_suspected
Review。didYouMean 包含一个可能的纠正,例如 gmial.com → gmail.com。
role_account
Review。本地部分是 admin@、info@、support@ 或 noreply@ 之类的角色地址,通常为共享而非个人使用。
implicit_mx
Review。该域名没有 MX 记录;邮件会回退到其 A/AAAA 地址,这在真实的邮件域名中很少见。
dns_unavailable
Review。DNS 查询失败或超时,因此该域名的邮件配置未知(mx.status: unknown)。这并不构成对该地址不利的证据。

批量检查

POST/v1/email/batch

在一次请求中检查 1–100 个地址,检查项和结果结构与 POST /v1/email/validate 相同,按输入顺序为每个地址返回一个结果。请发送 { "emails": [...] }。同一域名的地址共享一次 DNS 查询。每个地址计为一次请求,计入您套餐的每月上限;将超出上限的批量请求会以 429 monthly_limit_exceeded 被整体拒绝。对于每分钟速率限制,整个调用只算一次请求。仅限私密密钥。

请求

curl https://api.watch-ip.com/v1/email/batch \
  -H "Authorization: Bearer YOUR_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{"emails": ["user@gmail.com", "someone@mailinator.com"]}'

响应

{
  "results": [
    { "email": "user@gmail.com", "verdict": "accept", "reasons": [], ... },
    { "email": "someone@mailinator.com", "isDisposable": true, "disposableSource": "list", "verdict": "reject", "reasons": ["disposable_domain"], ... }
  ]
}

邮箱列表任务

POST/v1/email/jobs

在后台检查最多 100,000 个地址。请发送 JSON { "emails": [...], "filename": "..." },或不超过 10 MB 的 text/csv 请求体:使用标题为 email 的列(也可以是 e-mail、email address、email_address 或 mail,不区分大小写);如果没有标题指明该列,则使用第一列;自动识别逗号、分号和制表符分隔符。任务在创建时计费——每个不同地址(精确匹配)计一次请求,因此重复地址也会被检查,但只计费一次——将超出您每月上限的列表会被整体拒绝。如果任务的一部分在多次重试后仍无法处理,任务会被标记为 failed,未处理部分的额度将被退还。返回 202 及任务对象。仅限私密密钥;同样的任务也可以在控制台的 Email lists 页面上传和下载。

请求

curl https://api.watch-ip.com/v1/email/jobs \
  -H "Authorization: Bearer YOUR_SECRET_KEY" \
  -H "Content-Type: text/csv" \
  --data-binary @newsletter.csv

响应

{
  "id": "5b0d6f5e-8a51-4f7e-9d0e-2c1f3f7f8a11",
  "status": "queued",
  "source": "api",
  "filename": null,
  "total": 12840,
  "credits": 12512,
  "processed": 0,
  "summary": null,
  "createdAt": "2026-09-28T10:00:00.000Z",
  "completedAt": null,
  "expiresAt": "2026-10-05T10:00:00.000Z"
}

任务状态

GET/v1/email/jobs/{id}

返回同一个任务对象。请轮询直到 status 为 completed;轮询不计费。

status
queued → processing → completed。failed:列表的一部分在多次重试后仍无法处理;没有可用结果,未处理部分的额度已退还。expired:上传的地址和结果已在创建 7 天后删除。
total
提交的行数,包括重复行。
credits
已计费的请求数:每个不同地址一次。
processed
目前已检查的行数。
summary
完成后:按结论(accept/review/reject)及出现过的每个原因代码统计的行数。完成前为 null。
expiresAt
上传的地址和结果被删除的时间。

任务结果

GET/v1/email/jobs/{id}/results

下载一个 CSV,每个提交行对应一行,按提交顺序排列——包括重复行。列:email、normalized_email、verdict、reasons、syntax_valid、is_disposable、disposable_source、is_free_provider、is_role_account、did_you_mean、mx_status、mx_host。reasons 以分号分隔,空单元格表示 null,语法无效的地址其 mx_status 为空(未进行任何查询)。以 =、+、- 或 @ 开头的无效地址会被加上撇号前缀,以免电子表格软件将其作为公式执行。任务完成前返回 409,过期后返回 410。下载不计费。

请求

curl https://api.watch-ip.com/v1/email/jobs/5b0d6f5e-8a51-4f7e-9d0e-2c1f3f7f8a11/results \
  -H "Authorization: Bearer YOUR_SECRET_KEY" -o results.csv

注册检查

POST/v1/signup/check

在注册表单提交时从您的后端调用,一次调用即可根据邮箱地址和 IP 为注册评分(在浏览器中计算的结论可能被伪造)。请发送 { "email": "...", "ip": "...", "userAgent": "..." }——userAgent 为可选项。响应包含完整的邮箱检查结果(email)、IP 的国家和 ASN,以及——在包含安全数据的套餐中——其 VPN/Tor/数据中心/威胁指标(ip)、根据公开注册(RDAP)数据得出的邮箱域名注册天数(emailDomainAgeDays,未知时及对知名个人邮箱提供商为 null)、0–100 的评分(下列原因权重之和,上限为 100)和结论:60 分及以上为 reject,25 分及以上为 review,否则为 accept。在不含安全数据的套餐中,ip.security 为 null,评分仅使用邮箱信号,且 reasons 包含 ip_security_unavailable。计为一次请求。仅限私密密钥。

invalid_syntax
70
domain_not_found · no_mail_server · disposable_domain
各 60
ip_tor · ip_threat
各 40
ip_vpn
25
new_domain
25——邮箱域名注册不足 30 天
ip_datacenter
20——仅当该 IP 并非 VPN 或 Tor 出口时
automated_user_agent
20——提供的 userAgent 看起来像机器人或脚本
typo_suspected
15
role_account · implicit_mx
各 10
dns_unavailable
5
ip_security_unavailable
0——仅供参考:该套餐不含安全数据

请求

curl https://api.watch-ip.com/v1/signup/check \
  -H "Authorization: Bearer YOUR_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{"email": "jane@new-startup.io", "ip": "203.0.113.1"}'

响应

{
  "email": { "email": "jane@new-startup.io", "verdict": "accept", "reasons": [], ... },
  "ip": {
    "ip": "203.0.113.1",
    "country": "US",
    "asn": 64500,
    "asOrganization": "Example Hosting",
    "security": { "isTor": false, "isVpn": false, "isDatacenter": true, "isThreat": false, "isSanctionedNetwork": false }
  },
  "emailDomainAgeDays": 12,
  "score": 45,
  "verdict": "review",
  "reasons": ["new_domain", "ip_datacenter"]
}

限制

每个已检查的地址都计为一次请求,计入您套餐的共享每月上限——单个检查、批量中的每个地址、列表任务中的每个不同地址——一次注册检查计为一次请求。批量请求和列表任务会被整体接受或拒绝,绝不会部分执行。每分钟速率限制按 HTTP 调用次数计算,而不是按条目计算:一个最多包含 100 个 IP 或邮箱地址的批量请求只算一次请求,而其中每个条目仍会分别计入每月请求上限。列表任务的上传内容和结果会在任务创建 7 天后删除。DNS 查询的时间预算很短:当查询失败或超时时,结果会降级为 mx.status unknown 和原因 dns_unavailable,而不是报错。一次性域名数据合并自三个社区维护的开源列表,每隔几小时刷新一次,并以观察到为列表内域名提供服务的邮件服务器加以扩充——参见数据来源。非常新的一次性邮箱提供商可能尚未被标记。所有检查均在域名和地址层面进行:不会连接任何邮箱,因此任何结果都不能证明邮箱存在、归谁所有,或邮件能够送达。

相关页面