邮箱验证的正确姿势:为什么完美的正则不存在(以及该用什么代替)
2026-08-12
每个代码库的某个角落都藏着一条邮箱验证正则。有时候它只有五个字符;有时候是从标准文档里抄来的六千字节怪物。两个方向都错了,而为什么错的故事,是整个软件工程里”规范与现实的差距”最好的注脚之一。这篇文章讲清邮箱规范到底允许什么、为什么正则在这件事上永远翻车,以及真实系统最终沉淀下来的分层验证策略。
规范实际允许的东西(准备好惊讶)
邮箱地址主要由 RFC 5322 定义。格式是 本地部分@域名,而本地部分的规则比多数开发者想象的宽松得多。以下全部在技术上合法:
"John Doe"@example.com—— 引号字符串可以包含空格user+newsletter@gmail.com—— 加号寻址(Gmail 用户每天都在用)user.name+tag@sub.domain.co.uk—— 点和多级域名very.unusual."@".unusual.com@example.com—— 引号内可以藏一个 @ 符号作为本地部分内容user@[192.168.1.1]—— 用 IP 字面量代替域名用户@example.com—— 国际化邮箱扩展(RFC 6531)下的非 ASCII 本地部分
反向的规则也有牙齿:非引号形式的本地部分不能以点开头结尾、不能有连续的点;本地部分上限 64 字符、整个地址上限 254 字符;域名必须是合法主机名。
结论:“合法”地址的集合又大又怪,“非法”集合里也有长得很正常的边界情况。任何简单到可维护的正则都会误杀真实地址或放过无意义字符——通常两者兼得。
为什么正则永远让人失望
三个结构性问题注定了纯正则验证的失败:
- 语法是上下文相关的。
"或.是否合法取决于位置和引号状态。正则表达式出了名的不擅长嵌套、带状态的规则——完整 RFC 5322 语法编译成正则长达数千字符,不可读、不可审查、不可维护。 - 合法 ≠ 可送达。
correct@format-but-fake-domain.xyz能通过任何语法检查。地址格式正确跟邮箱是否存在毫无关系,而后者往往才是你真正关心的。 - 标准在漂移。 国际化地址、新顶级域(
.museum、.technology)、各家服务商的怪癖,意味着任何硬编码的模式都会过时。老正则里烤死的顶级域长度限制({2,4})十多年来一直在误杀完全正常的地址。
诚实的说法是:正则只能检查形状,仅此而已。快速检查形状——表单字段里、日志分析里、数据清洗脚本里——用邮箱验证器这类工具正合适。只是别把”通过形状检查”和”这是个真实收件箱”混为一谈。
真正有效的策略:分层
真实系统把邮箱验证分成由便宜到昂贵的三层,任何一层失败就停止:
第一层——语法(客户端,即时)。 故意宽松地检查:长得像 某串@某串.某串 吗?浏览器内置的 <input type="email"> 或一条短模式如 ^[^\s@]+@[^\s@]+\.[^\s@]+$ 足以抓住拼写错误——95% 的情况——而不会误杀奇怪但真实的地址。忍住收紧它的冲动。这一层的目标是帮用户改掉 john@gmail,com,不是执行 RFC。
第二层——域名(服务端,毫秒级)。 通过 DNS 检查域名是否有 MX(或 A)记录。这能干掉 john@gmal.com 和整类假注册,且对用户零打扰。如果滥用是个问题,一次性邮箱黑名单也可以放在这一层。
第三层——邮箱本身(唯一权威检查)。 发一封带链接或验证码的确认邮件。这是唯一能证明地址存在且由用户控制的技术。每个认真的注册流程都终结于此——这也是为什么过度设计前两层是浪费——反正第三层才是真相来源。
实用守则
- 为拼写错误而验证,不为合规而验证:格式上宽松,意图上严格。
- 永远不要拒绝本地部分里的
+。 加号寻址合法且深受重度用户喜爱;封禁它就是封禁你最活跃用户的过滤工作流。 - 去掉首尾空白、域名转小写(域名不区分大小写),但本地部分的大小写别动——技术上它可以区分大小写。
- 只有在垃圾/滥用真的伤害到你时才拒绝一次性邮箱域名;确实有注重隐私的合法用户在用它们。
- 测试你的验证逻辑时,测试用例要从上面”奇怪但合法”和”正常但非法”的清单里选,而不是从直觉里选。正则测试器适合拿这批用例迭代第一层的模式,需要扩展语法时正则参考可以查。
速查表
- 邮箱 =
本地部分@域名;本地部分 ≤ 64 字符,整个地址 ≤ 254。 - 合法但奇怪:引号字符串、
+tag、IP 字面量域名、国际化名字。 - 正则只查形状——永远查不了可送达性。
- 有效组合:宽松语法检查 → DNS/MX 检查 → 确认邮件。
- 确认邮件是”真实且用户可控邮箱”的唯一证明。
- 别封
+,别限制顶级域长度,别把本地部分转小写。