我构建了一个 Email 验证库并发布到 npm。以下是我学到的全部内容
Source: Dev.to
故事
我在过去的几周里从零开始构建了一个 email‑validation 库 并将其发布到 npm。并不是因为世界急需另一个 npm 包,而是因为我想 深入了解电子邮件验证的实际工作原理。现有的解决方案让我感到沮丧,于是我决定自己动手实现。
在本文中,我将分享:
- 我为何创建它
- 我的收获
- 使其 比其他方案快 3 倍 的技术决策
- 如何使用相同的方法构建你自己的 npm 包
让我们开始吧…
我将要覆盖的内容
- 为什么我开始这个项目
- 大多数开发者不知道的 电子邮件验证的5层
- 我如何让它比竞争对手 快 3 倍
- 技术栈的决策(以及原因)
- 如何发布你的第一个 npm 包
- 我下次会做哪些不同的事情
为什么要再建一个邮件验证器?
我在一个项目中使用了 deep-email-validator。它能工作,但有几个问题让我很烦恼:
- TypeScript 类型已经过时(仍然是 3.8 版)
- 没有批量验证的支持
- 没有缓存(对同一个邮箱进行两次验证会重复全部工作)
- 错误信息都是像 “Invalid email” 这样的通用字符串
- 正则表达式验证并未符合 RFC 5322 标准
我想,“做一个更好的东西有多难?”
这句话听起来很自信。结果发现,邮件验证比大多数人想象的要复杂得多——这正是这个项目值得去构建的原因。
电子邮件验证的5层
大多数开发者认为电子邮件验证只是一条正则表达式检查。这大概只占**20 %**的完整验证。要实现生产就绪的验证器,需要进行以下检查:
第 1 层 – 正则(格式验证)
电子邮件看起来像电子邮件吗?它必须符合 RFC 5322。
技术上有效的地址示例:
"john doe"@example.com(带引号的字符串)user+tag@example.com(加号地址)user@[192.168.1.1](IP 地址域)
许多 Stack‑Overflow 上的正则会拒绝其中一半。
第 2 层 – 拼写错误检测
user@gmial.com 在语法上是合法的,但 Gmail 并不存在于 gmial.com。
此层捕捉常见的拼写错误并给出建议,例如 “您是想输入 gmail.com 吗?”
第 3 层 – 临时邮箱检测
Mailinator、Guerrillamail、10 Minute Mail…
已有 > 40 000 家临时邮箱服务。如果不阻拦它们,你的数据库会被大量假用户占满。
第 4 层 – MX 记录验证
即使域名看起来合法,它真的有邮件服务器吗?
对 MX 记录进行 DNS 查询即可判断该域名是否能够接收邮件。没有 MX → 无效。
第 5 层 – SMTP 验证
最终关卡:连接邮件服务器并询问 “此邮箱是否存在?”
这一步较慢(网络调用),且有时不可靠(服务器可能阻止验证),但在需要确定性时,这是唯一可行的办法。
Source: …
让速度提升 3 倍
原始的 deep-email-validator 顺序 验证电子邮件,且没有缓存,每一次 DNS 和 SMTP 检查都会访问网络。我希望 在 5 秒内处理 100 封邮件。
方案 1 – 并发处理
使用可配置的并发度并行验证大量邮件:
const result = await validateBulk(emails, {
concurrency: 10,
onProgress: (completed, total) => {
console.log(`Progress: ${completed}/${total}`);
},
});
10 个并发验证 ≈ 提升 10 倍的批量处理速度。
方案 2 – 内置限流
频繁请求邮件服务器会导致被列入黑名单。我加入了 令牌桶 限流器:
await validateBulk(emails, {
rateLimit: {
perDomain: { requests: 10, window: 60 }, // 每个域每分钟 10 次请求
global: { requests: 100, window: 60 }, // 全局每分钟 100 次请求
},
});
防止滥用的同时保持高性能。
方案 3 – 提前退出
如果正则匹配失败,就没有必要检查 MX 记录。提前退出 选项会在第一次失败时停止验证,从而快速拒绝无效邮件:
- 💻 GitHub:
- 📚 Docs:
接下来是什么?
- 内存 LRU 缓存 (v1.1)
- 增强的声誉评分,支持可配置权重
- 用于快速验证的 CLI 工具
- 可能的浏览器构建
如果你觉得这有用,请在 GitHub 上给仓库加星——这比你想象的更有帮助。如果你用它构建了很酷的东西,请告诉我;我很想看到你的创作。