Python 邮箱验证:从代码中检查可投递性
使用维护良好的库验证地址格式,然后通过 Python 代码检查单个地址、100 个批量地址或整个文件的可投递性。

一份 Python 邮箱验证指南:涵盖本地格式验证、单个及多个地址的可投递性检查,以及异步批量任务。
Python 中的邮箱验证包含两个部分。首先使用诸如 email-validator 之类维护良好的库在本地验证格式,然后通过从代码调用 API 来检查可投递性:使用 EmailCheckPro 的 POST /api/v1/check 检查单个地址,使用 POST /api/v1/batch-check 在一次同步请求中检查 1–100 个地址,或者针对整个文件使用批量任务(轮询频率不得超过每 30 秒一次)。每次完成的检查都会报告检查时的可投递或不可投递状态,部分地址则保持无法判定状态。该检查不会向目标地址发送任何内容。
Python 中的格式验证与可投递性检查
大多数关于此主题的 Python 教程混合了三种技术:正则表达式、域名 DNS 查询以及与收件人邮件服务器通信的脚本。它们回答的问题各不相同,且最后一种方法存在实际风险。
| 技术 | 提供的信息 | 主要局限性 |
|---|---|---|
| 正则表达式或验证库 | 输入内容看起来像一个完整的地址 | 无法提供关于邮箱本身的信息 |
| 域名 DNS 查询 | 域名看起来已配置为可接收邮件 | 无法提供关于具体地址的信息 |
| 自建邮件服务器脚本 | 有时能判断收件人是否被接受 | 许多服务器会接受所有请求或拒绝未知调用者,且您的 IP 可能会被列入黑名单 |
| 可投递性检查 API | 检查时的可投递或不可投递状态,且无需发送任何内容 | 部分地址保持无法判定状态 |
实用的 Python 工作流会对每个输入使用第一行技术,并对重要地址(如新注册、导入数据或即将发送邮件的列表)使用最后一行技术。确认链接应作为单独的步骤,用于获取许可和确认所有权。
第 1 步:使用 email-validator 验证格式
email-validator 软件包 提供可读的错误消息和地址的规范化形式,这比手写的模式更适合作为起点。
from email_validator import validate_email, EmailNotValidError
def screen_format(raw: str) -> str | None:
try:
result = validate_email(raw.strip(), check_deliverability=False)
return result.normalized
except EmailNotValidError:
return None
这里有两个细节很重要:
- 关闭其 DNS 步骤。 默认情况下,该库会查询 DNS 以查看域名是否可以接收邮件。这是一个域名级别的信号,会增加延迟,而可投递性 API 能更直接地回答这个问题,因此
check_deliverability=False可以保持此层级的快速且离线运行。 - 存储规范化后的值。 该库会将域名转换为小写并规范化 Unicode,这可以防止因拼写不同而导致的重复录入。
格式错误的条目应返回给用户或放入修复列表中。这不属于不可投递结果,且 OWASP 指南 建议不要使用会拒绝有效地址的严格自定义模式。
第 2 步:检查单个地址的可投递性
对于注册视图或个人资料编辑,请使用 requests 从服务器代码调用单个端点。
import os
import requests
API_BASE = os.environ["EMAILCHECK_API_BASE"] # 来自 API 文档
session = requests.Session()
session.headers.update(build_headers()) # 身份验证标头需完全按照文档要求
def check_one(email: str) -> str:
try:
resp = session.post(f"{API_BASE}/api/v1/check",
data=build_check_body(email), # 请求体需按照文档要求
timeout=(3.05, 10))
return to_outcome(resp) # "deliverable" | "undeliverable" | "undetermined"
except requests.RequestException:
return "not_completed"
build_headers、build_check_body 和 to_outcome 是根据 EmailCheckPro API 文档编写的小型辅助函数,确保身份验证和字段细节统一且符合已发布的契约。返回纯字符串可使代码库的其余部分独立于响应格式。
务必设置超时。 Requests 文档 指出,请求默认不会超时,且元组可以分别设置连接和读取限制。请根据您页面的容忍度选择数值;上述数字仅为示例。
然后根据四种状态进行分支处理:
- 可投递: 继续操作并保存检查日期。
- 不可投递: 要求用户提供其他地址。
- 无法判定: 例如 catch-all 地址。实时 API 会返回业务代码而非结果,且该检查不计费。使用标记进行接收。
- 未完成: 超时或网络错误。使用标记进行接收,并稍后从队列中重新检查。
第 3 步:每个请求最多检查 100 个地址
管理工具、小型导入和夜间作业通常涉及几十或几百个地址。 POST /api/v1/batch-check 接受 1–100 个地址并在同一响应中返回结果,结果顺序与输入顺序一致。
def chunks(items, size=100):
for start in range(0, len(items), size):
yield items[start:start + size]
def check_many(emails: list[str]) -> dict[str, str]:
outcomes = {}
for group in chunks(emails):
items = post_multi(group) # POST /api/v1/batch-check
for email, item in zip(group, items):
outcomes[email] = item_outcome(item) # 无完成结果 -> "undetermined"
return outcomes
由于顺序得以保留,zip 将每个项目映射回生成它的地址。每个项目还会说明是否存在完成的结果。只有标记为 1 的项目才表示可投递或不可投递;其他任何情况都归入无法判定或未完成组,绝不会归入不可投递。
在分块前对规范化后的地址进行去重,以确保同一个邮箱在一次运行中不会被检查两次。对于没有代码的几百个地址,仪表板的实时检查功能每次最多可处理 500 个。
第 4 步:针对整个文件运行批量任务
一旦源数据是导出文件,批量任务是更好的选择。它是异步的,因此请从脚本、定时任务或诸如 Celery 之类的 worker 中运行,而不是从 Web 视图中运行。
- 写入文件。 生成 TXT 或 CSV 文件,每行包含一个完整的地址。Python 内置的文件写入功能足以处理 TXT;当您从电子表格导出时,csv 模块 会很有帮助。
- 提交并保存任务引用到您的数据库中,包含文件名和时间,以便重启的 worker 可以恢复任务。
- 耐心轮询,间隔 30 秒或更长时间:
import time
def run_bulk(path: str) -> str:
task_ref = submit_file(path) # POST /api/v1/bulk-tasks
save_task(task_ref, path) # 确保 worker 重启后任务依然存在
while True:
status = get_status(task_ref) # GET /api/v1/bulk-tasks/{id}
if status.finished:
return status.result_link # 12 小时内有效
time.sleep(30) # 轮询频率不得高于此
- 下载并合并。 成功的任务会返回一个 CSV 链接,该链接有效期为 12 小时;如果过期,请再次查询同一任务以获取新链接。使用
csv.DictReader读取它,并按邮箱地址而非行号进行连接,因为无效和重复的行在准备阶段已被移除。
可投递性 CSV 将每个地址与其结果配对。对于 Gmail、Yandex 和 Mail.ru 列表,邮箱头像检测功能会添加头像列;即使存在头像,其头像链接也可能为空。各产品的任务限制列在 API 文档中。
保持 Python 集成的可靠性
- 将密钥保存在代码之外。 从环境变量或密钥存储中读取;它会消耗 Web 检查、API 调用、批量任务和 MCP 访问共享的账户余额。
- 复用
Session。 它可以在多次调用中保持连接打开,这有助于处理多地址分块的循环。 - 记录日期。 结果描述的是检查时的地址状态,因此请存储日期并在大规模发送前重新检查旧行。
- 队列重试。 无法判定、失败和无效的检查不计费,但立即重试很少会改变结果。请设置延迟和上限来安排重试。
- 测试分支。 模拟调用 API 的辅助函数,并断言每个状态都能到达正确的消息或队列。
- AI 笔记本和助手:
https://emailcheckpro.com/mcp的 MCP 端点支持单个检查和最多 100 个地址;文件任务仍需使用 REST API。
常见问题解答
哪种 Python 库最适合邮箱格式验证?
email-validator 是一个广泛使用的选择,因为它提供清晰的错误消息,支持国际化域名并返回规范化的地址。无论团队选择哪种库,关键在于在表单、导入和脚本中使用统一的真值来源,并在单独的可投递性检查已经涵盖地址是否可接收邮件时,禁用可选的 DNS 查询。
团队如何从 Python 检查大型 CSV 地址文件?
编写一个每行包含一个完整地址的 TXT 或 CSV 文件,将其作为批量任务提交,并从后台作业中以不超过每 30 秒一次的频率轮询其状态。任务成功后,在 12 小时内下载结果 CSV,或再次查询任务以获取新链接,然后按邮箱地址合并结果。
为什么不使用自建的 Python 邮件服务器脚本来验证邮箱?
许多邮件服务器会接受所有收件人、延迟未知调用者或阻止重复连接,因此脚本会返回大量不确定的答案,并可能导致发送 IP 被列入黑名单。托管的可投递性检查在不向地址发送任何内容的情况下返回可投递或不可投递结果,并将无法确定的地址标记为无法判定,而不是进行猜测。
了解更多
选择符合您工作流下一步的产品信息。