应优先用net/mail.parseaddress做rfc 5322语法解析,而非正则;再通过net.lookupmx查mx记录,最后用smtp模拟rcpt to验证邮箱存在性,全程需控制并发、设超时与退避。

用 net/mail 解析邮箱格式,别只靠正则
纯正则校验邮箱(比如 ^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}$)会放过大量语法错误地址,也会误杀合法但冷门的格式(如带引号的本地部分、+标签)。Go 标准库的 mail.ParseAddress 或 mail.ParseAddressList 才是可靠起点——它按 RFC 5322 实际解析,能立刻暴露 invalid character、missing @ 这类硬伤。
实操建议:
- 对每个邮箱字符串调用
mail.ParseAddress(email),忽略Name字段,只取Address(即标准化后的local@domain) - 若返回
err != nil,直接判定格式非法,**不进入后续 SMTP 检查** - 注意:该函数不验证域名是否存在或是否可路由,仅做语法层校验
SMTP 连接前必须查 MX 记录,否则 99% 连接失败
直接对邮箱域名发 net/smtp 连接(如 smtp.gmail.com:25)是典型误区。真实邮件服务器不会监听所有域名的 25 端口,且多数对外关闭 SMTP 连接权限。正确路径是先查 MX 记录,拿到该域名实际负责收信的主机列表。
实操建议:
- 用
net.LookupMX(domain)获取 MX 记录,返回非空切片才继续 - 若返回
no such host或no MX record,说明域名不存在或未配置邮件服务,直接标记“域名无效” - 优先尝试第一个 MX 主机(权重最低),超时设为 5 秒以内,避免卡住整个批量流程
用 net/smtp 发 HELO/MAIL FROM/RCPT TO,但别发实际邮件
SMTP 校验本质是模拟发信流程的前三步:握手(HELO)、声明发件人(MAIL FROM)、声明收件人(RCPT TO)。只要 RCPT TO 返回 250(OK),就说明该邮箱地址被目标服务器接受——这比 DNS 验证更接近真实存在性。
初始化并管理阿里云SDK Go 客户端,涵盖 sync.Once 单例、goroutine 安全、endpoint 与 region 配置、VPC 端点及调试。
实操建议:
- 连接 MX 主机后,立即发
HELO(不是EHLO,部分老服务器不支持扩展命令) -
MAIL FROM用一个固定测试邮箱(如test@yourdomain.com),确保格式合法且域名有 MX -
RCPT TO填待校验邮箱,**收到 250 即认为通过,收到 5xx(如 550 User unknown)即判定不存在** - 收到 4xx(临时错误)应跳过,不重试——可能是对方限流,不代表邮箱无效
批量校验必须加并发控制和退避,否则会被封 IP
连续高频连接不同 MX 服务器,极易触发反爬机制(如 Postfix 的 smtpd_delay_reject = yes 或防火墙速率限制)。单机每秒超过 2–3 次 SMTP 连接,大概率被目标服务器拒绝或延迟响应。
实操建议:
- 用
semaphore控制并发数,建议 ≤ 5 goroutine 同时进行 SMTP 连接 - 每次连接失败(超时/拒绝)后,对该域名加 1–3 秒随机退避,避免雪崩式重试
- 对同一域名的多次校验结果缓存 1 小时——MX 记录和邮箱有效性短期不会突变
- 记录失败详情(如
timeout、refused、550),方便区分是网络问题还是邮箱真实不存在
真正难的不是写通 SMTP 流程,而是平衡校验精度和对目标服务器的友好度。漏掉几个真实邮箱,总比被整个邮件服务商拉黑强。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










