☰
Mailcheck 2.0.0-beta.1 发布指南:内置 TypeScript 类型、现代域名后缀保护与缺失后缀补全
2026/10/14 7:24:33 网站建设 项目流程
  • 开发工具

【免费下载链接】mailcheck

Reduce misspelled email addresses in your web apps.

项目地址:https://gitcode.com/gh_mirrors/ma/mailcheck
点击查看免费下载

Mailcheck 2.0.0-beta.1 是该项目迈向 2.0 的第一个预发布版本:它在不改变既有 JavaScript 调用 API的前提下,随包内置了 TypeScript 类型声明,重写了域名匹配行为(保护.ai、.io、.app等现代真实后缀,避免被"过度纠错"),并新增了缺失域名后缀的补全能力。本文以 Releases/2.0.0-beta.1.md 发布说明为主线,结合仓库源码与测试用例,逐条解读本次改版的行为细节、升级影响与打包/测试覆盖情况,帮助你评估集成风险并规划升级路径。

一、版本概览:一次"行为收紧 + 类型补齐"的 Beta

2.0.0-beta.1 的核心变化可以归纳为三点,全部围绕"更少误报、更稳建议"展开:

  1. TypeScript 定义随包内置:无需再单独安装@types/mailcheck;
  2. 域名匹配更新:引入离线 IANA 根域快照,把"真实存在的后缀"与"可纠正的目标"区分开;
  3. 缺失后缀补全:sample@gmail、sample@gmail.现在可以直接建议sample@gmail.com。

最关键的一条约束是:现有的 JavaScript API 完全不变。方法、选项、回调参数与返回值形状全部保持原样,没有需要适配的新包装器,也没有新的识别选项要配置。这意味着从 1.1.2 升级到 2.0 时,前端调用代码几乎无需改动,行为层面的变化才是需要关注的焦点。

二、邮箱建议行为:六条行为变更逐一解读

发布说明把本次行为改动总结为六个要点,下面结合 src/mailcheck.js 的实现逐一展开。

1. 现代域名后缀不再被"纠正":1438 个 IANA 后缀的离线快照

变化:地址处于.ai、.io、.app等已被 IANA 收录的真实后缀上时,不再因为"看起来很像"而被改写到其他后缀。

源码依据:源码顶部维护了一个名为validTopLevelDomains的离线快照(src/mailcheck.js),注释明确标注:

  • 快照版本为2026091400(2026-09-14),数据源是 IANA 根区 TLD 列表;
  • 共包含1,438 个根域后缀;
  • 它仅用于识别(Recognition),不是模糊纠错目标,也不做运行时联网查询——快照更新必须通过新构建发布。

在suggest()中,从地址拆出的域名根(最后一个.之后的部分)如果命中该快照,或者命中了调用方通过topLevelDomains显式配置的后缀,就被视为knownTopLevelDomain(src/mailcheck.js),随后纠错目标会被收缩为"仅保留与当前后缀一致的域名":

var root = emailParts.domain.substring(emailParts.domain.lastIndexOf('.') + 1); var knownTopLevelDomain = validTopLevelDomains.indexOf(root) !== -1 || !!(topLevelDomains && topLevelDomains.indexOf(emailParts.topLevelDomain) !== -1); // A recognized suffix must not become a different suffix (e.g. .co -> .com). var matchingDomains = domains; if (knownTopLevelDomain && domains) { matchingDomains = []; for (var i = 0; i < domains.length; i++) { if (domains[i].substring(domains[i].indexOf('.') + 1) === emailParts.topLevelDomain) { matchingDomains.push(domains[i]); } } }

测试印证:person@company.ai、person@company.io、person@company.app、person@company.dev、person@company.zip、person@company.museum等均被列入legitimate名单并断言"不产生建议"(spec/correctness.test.js)。此外spec/correctness.test.js中还有专门的用例,遍历ai/io/app/dev/me/co/om/zip/mov/xyz/tech等 30 个后缀,在两种不同的domains列表顺序下均验证"独立公司地址不被改写"。

设计意图:这是从"激进纠错"向"保守建议"的一次明确转向——宁可漏掉一个真实的拼写错误,也不要对合法地址给出错误建议。

2. 识别更多邮件服务商:Proton、HEY、Fastmail、Tuta 进入默认列表

变化:默认纠错目标列表新增了 Proton(proton.me、protonmail.com、pm.me)、HEY(hey.com)、Fastmail(fastmail.com)、Tuta(tuta.com、tutanota.com、tutamail.com)。

源码依据:defaultDomains定义于 src/mailcheck.js,本次新增的条目紧跟在原有服务商之后:

defaultDomains: ['msn.com', 'bellsouth.net', 'telus.net', 'comcast.net', 'optusnet.com.au', 'earthlink.net', 'qq.com', 'sky.com', 'icloud.com', 'mac.com', 'sympatico.ca', 'googlemail.com', 'att.net', 'xtra.co.nz', 'web.de', 'cox.net', 'gmail.com', 'ymail.com', 'aim.com', 'rogers.com', 'verizon.net', 'rocketmail.com', 'google.com', 'optonline.net', 'sbcglobal.net', 'aol.com', 'me.com', 'btinternet.com', 'charter.net', 'shaw.ca', 'proton.me', 'protonmail.com', 'pm.me', 'hey.com', 'fastmail.com', 'tuta.com', 'tutanota.com', 'tutamail.com'],

测试印证:spec/correctness.test.js 中every bundled provider is left alone用例遍历Mailcheck.defaultDomains全部条目,断言Mailcheck.run({ email: 'Person@' + domain })均返回undefined(不产生建议)——即所有内置服务商的精确地址都得到保护。

3. 缺失后缀补全:sample@gmail→sample@gmail.com

变化:sample@gmail和sample@gmail.现在会建议sample@gmail.com。补全复用现有的domains列表(或默认列表),不引入新选项;且必须满足"名字精确 + 存在一个完整的全域名匹配"两个条件:

  • 不基于部分名字猜测(gmai不会补全);
  • 不在多个后缀之间做选择(gmail.com与gmail.co.uk同时存在时不补全)。

源码依据:src/mailcheck.js 的补全逻辑先校验域名是否形如合法单标签(含可选的尾部点),再在domains中寻找以名字 + '.'为前缀的完整域名:

if (/^a-z0-9?\.?$/.test(emailParts.domain) && emailParts.domain.indexOf('xn--') !== 0) { if (domains && domains.indexOf(emailParts.domain) !== -1) { return false; } var prefix = emailParts.domain.replace(/\.$/, '') + '.'; var completion = false; for (var d = 0; domains && d < domains.length; d++) { if (domains[d].indexOf(prefix) === 0 && domains[d].length > prefix.length) { if (completion && completion !== domains[d]) { return false; // 多个候选 → 不补全 } completion = domains[d]; } } return completion ? { address: emailParts.address, domain: completion, full: emailParts.address + '@' + completion } : false; }

测试印证(spec/correctness.test.js):

  • sample@gmail、Sample+Tag@GMAIL、sample@gmail.、person@icloud、person@proton分别补全为sample@gmail.com、Sample+Tag@gmail.com、sample@gmail.com、person@icloud.com、person@proton.me;
  • 补全结果的地址再次运行会返回undefined(结果稳定,不会连锁纠错);
  • 歧义场景(domains: ['gmail.com', 'gmail.co.uk']或反序)一律不补全;
  • g、gm、gmai、gmial、unknowncompany等部分名/未知名均不补全;
  • 显式配置了单标签域名(domains: ['gmail', 'gmail.com'])时也不扩展补全。

4. 平局不再按列表顺序取胜

变化:当两个全域名候选与输入的距离完全相等时,不再产生任何建议(此前会按列表顺序挑第一个)。

源码依据:内部辅助函数mailcheckClosestMatch(src/mailcheck.js)专门跟踪ambiguous标志——一旦发现相同距离的第二个不同候选,即标记为歧义:

if (dist < minDist) { minDist = dist; closestDomain = domains[i]; ambiguous = false; } else if (dist === minDist && domains[i] !== closestDomain) { ambiguous = true; } return { domain: minDist <= threshold && !ambiguous ? closestDomain : false, ambiguous: minDist <= threshold && ambiguous };

测试印证:cat.com面对['bat.com', 'hat.com']或['hat.com', 'bat.com']均返回false;但重复项不算歧义(['bat.com', 'bat.com']仍返回bat.com);精确匹配优先(['bat.com', 'cat.com']返回cat.com)(spec/correctness.test.js)。同时mailcheckClosestMatch的注释点明了设计动机:把"歧义"与"无匹配"区分开,避免平局时回退到二级域名猜测(src/mailcheck.js)。

5. 保留本地部分(local-part)的大小写

变化:Sample.Name+Tag@gmial.com建议为Sample.Name+Tag@gmail.com——只有域名被小写化,@之前的本地部分原样保留(包括大小写与+Tag标签)。

源码依据:src/mailcheck.js 只对拆分出的domain、secondLevelDomain、topLevelDomain调用toLowerCase(),address(本地部分)从不触碰。同时run()仍保留其既有的encodeEmail()编码步骤(src/mailcheck.js),而低层suggest()则直接接收调用方传入的原始字符串。

测试印证:François、a%%^^``{{||}}、"Foo@Bar"、<script>alert("x")</script>等本地部分在run()中经编码、在suggest()中原样保留(spec/correctness.test.js、spec/correctness.test.js)。

安全提示:由于run()的 URI 编码并非 HTML 消毒器,展示用户输入时应使用textContent、jQuery 的.text()或框架的转义渲染,不要使用innerHTML(index.d.ts 的类型注释同样强调了这一点)。

6. 零距离阈值 = 仅精确匹配

变化:将domainThreshold(或通过findClosestDomain传入的阈值)设为0时,距离匹配只允许完全相等的字符串。

测试印证:Mailcheck.findClosestDomain('gmial.com', ['gmail.com'], undefined, 0)返回false,而Mailcheck.findClosestDomain('gmail.com', ['gmail.com'], undefined, 0)返回'gmail.com'(spec/correctness.test.js)。三个默认阈值domainThreshold、secondLevelThreshold、topLevelThreshold当前均为2(src/mailcheck.js),它们是公开的可变属性,也是本次 TypeScript 类型覆盖的一部分。

建议的输出方式没有变

所有建议仍然通过既有的suggested回调或run()的返回值输出;Mailcheck 永远不会自动替换输入框中的地址。渲染建议是应用层自己的职责(参考 examples/index.html 中 jQuery 示例的做法)。

三、TypeScript:类型随包内置,API 零变化

覆盖了哪些类型面

发布说明声明:类型覆盖了 options、suggestion、自定义距离函数、回调返回值,以及可变的默认值(defaultDomains、defaultSecondLevelDomains、defaultTopLevelDomains与三个阈值均为let声明,见 index.d.ts)。

类型声明分布在以下文件(均在 package.json 的types字段中登记):

  • index.d.ts:Suggestion、EmailParts、DistanceFunction、Options、RunOptions,以及run/suggest/findClosestDomain/sift4Distance/splitEmail/encodeEmail的签名;
  • src/mailcheck.d.ts 与 src/mailcheck.min.d.ts:直接导入源码/压缩构建时的类型入口;
  • jquery.d.ts:可选的 jQuery 插件声明。

五种消费形态全部覆盖

仓库在 spec/package/ 下提供了五种消费形态的类型 fixture:

  1. CommonJS:spec/package/commonjs.cts 使用import Mailcheck = require('mailcheck'),同时验证直接导入mailcheck/src/mailcheck.js与mailcheck/src/mailcheck.min.js;
  2. ESM interop:spec/package/esm.mts 使用默认导入(需要esModuleInterop),并验证类型导入import type { Suggestion, RunOptions } from 'mailcheck';
  3. 浏览器全局:spec/package/browser.ts 声明Mailcheck全局变量;
  4. 直接源码导入:mailcheck/src/mailcheck.js与压缩构建均有对应类型;
  5. 可选的 jQuery 声明:spec/package/jquery.ts 通过import type {} from 'mailcheck/jquery'接入,类型注释提醒:该插件返回void(不可链式调用),回调参数依次为元素与建议对象。

类型层面的三个设计要点

  • 回调返回值独立推断:run()默认返回Suggestion | undefined;一旦提供suggested/empty回调,返回类型由回调的返回值联合推断(index.d.ts)。spec/package/commonjs.cts中suggested: suggestion => suggestion.full.length、empty: () => null时结果被推断为number | null;
  • 低层 API 语义区分:suggest()与findClosestDomain()无匹配时返回false而非undefined,且纠错列表必须显式传入,不像run()有默认值(index.d.ts);
  • 编译期守护:fixture 里用@ts-expect-error断言"不存在的validTopLevelDomains选项"、"suggest仍是五参数"等错误场景必须报错(spec/package/commonjs.cts)。

TypeScript 使用者不再需要单独的@types/mailcheck包;如果已安装该包且与内置类型冲突,应按 README.md 的建议将其移除。Mailcheck 依旧保持零运行时依赖、零运行时网络请求(package.json 的dependencies为空)。

四、升级时必须核对的行为(Breaking-ish 清单)

这四条是发布说明明确提示"升级时需检查"的行为变化,直接决定了线上表现是否可接受:

  1. gmail.co现在会被放行:.co是真实后缀,不再被建议为gmail.com。这是刻意选择"漏掉真实拼写错误,优于给出错误建议"。测试中person@gmail.co、person@hotmail.co均列入legitimate名单(spec/correctness.test.js),person@gmil.ai同样被保护。

  2. 未知或歧义的无后缀名字不再补全:sample@unknowncompany不补全;通过domains选项传入的列表会整体替换默认列表(src/mailcheck.js 中opts.domains = opts.domains || Mailcheck.defaultDomains)。注意空数组domains: []也是有效的"替换"——它会关闭所有补全(spec/correctness.test.js 验证了替换不影响全局默认列表)。

  3. Unicode/punycode 域名与不支持的子域布局一律不猜测:person@bücher.de、person@xn--bcher-kva.de、person@example.рф均返回undefined(spec/correctness.test.js)。代码层面通过/(^|\.)-|-(\.|$)|(^|\.)xn--/与xn--前缀检查主动放弃这类输入(src/mailcheck.js)。显式配置的复合后缀(如co.uk、com.au、co.nz)仍然受支持——它们必须在topLevelDomains中列出才被认可,本实现并非公共后缀解析器。

  4. Mailcheck 是拼写建议器,不是地址验证器:它不做投递性检查,被拒绝的建议不应阻断注册流程。类型声明同样写明 "Offline email-domain typo suggestions, not validation or deliverability checks"(index.d.ts)。

五、发布包与测试覆盖

归档内容与构建方式

发布说明提到的mailcheck-2.0.0-beta.1.tgz由仓库根目录的 cut_release.sh(转发至 script/cut-release.js)构建,归档仅包含:

  • 运行时 src/mailcheck.js 与压缩构建 src/mailcheck.min.js;
  • TypeScript 声明(index.d.ts、src/mailcheck.d.ts、src/mailcheck.min.d.ts、jquery.d.ts);
  • 清单文件(package.json、bower.json、mailcheck.jquery.json)、README.md 与 LICENSE。

测试、构建工具和 vendored jQuery 一律不打包(PACKAGE_FILES白名单见 script/cut-release.js)。

cut_release.sh的用法(预发布与正式版通用):

./cut_release.sh 2.0.0-beta.1 # 生成 Releases/mailcheck-2.0.0-beta.1.tgz ./cut_release.sh 2.0.0 # 生成 Releases/mailcheck-2.0.0.tgz ./cut_release.sh 2.0.0-beta.1 --dry-run # 仅预览输出路径

打包流程在临时副本中更新package.json、jQuery 清单与源码 banner 的版本号、用构建代码重建压缩文件、以npm pack --offline --ignore-scripts生成归档,并校验版本元数据一致性与归档文件名;绝不覆盖已存在的归档,也不执行发布(不推送、不打 tag、不创建 GitHub Release,无需 npm 登录)(script/cut-release.js)。该脚本要求开发依赖已安装,且打包前会校验package.json与源码 banner 的版本必须一致。

测试矩阵

发布说明声明的覆盖范围在仓库中均有对应落点:

覆盖项说明仓库落点
原始 Jasmine 套件遗留核心规范spec/mailcheckSpec.js、spec/spec_runner.html
回归与正确性用例对源码与压缩构建同时执行spec/correctness.test.js
包消费者测试在隔离临时目录安装 tarball 后编译运行 CJS/ESM 导入script/test-package.js、spec/package/
TypeScript 类型检查严格模式下的 CJS/ESM/浏览器全局/jQuery fixturepackage.json 的test:types
60 个浏览器测试Chromium、Firefox、WebKit 三引擎 × 源码/压缩两种构建playwright.config.js、spec/e2e/
发布打包检查构建并检查真实预发布/正式归档spec/release.test.js、package.json 的test:release

浏览器测试同时覆盖了纯 JavaScript fixture与真实 jQuery 示例(examples/index.html 在测试中被本地 jQuery 替代 CDN 引用,分别以 jQuery 1.12.4 与 3.7.1 运行),并检查 blur 回调、输入不被改写、陈旧建议清除与本地部分的安全渲染(README.md)。

明确不覆盖的范围:Internet Explorer 与真实邮件投递。

发布状态

这是一个仅供集成测试的 Beta 归档,尚未发布到 npm。集成时请直接使用本仓库 src/mailcheck.min.js 或 src/mailcheck.js,或自行用cut_release.sh生成本地归档;npm install mailcheck安装到的仍是已发布的旧版本,而非本次 Beta 行为。

六、实操速查:验证与接入

在 Node 中快速验证新行为

const Mailcheck = require('mailcheck'); // 指向本仓库源码或本地归档 // 1. 现代后缀保护 Mailcheck.run({ email: 'person@company.ai' }); // undefined // 2. 缺失后缀补全 Mailcheck.run({ email: 'sample@gmail' }).full; // 'sample@gmail.com' // 3. 大小写保留 Mailcheck.run({ email: 'Sample.Name+Tag@gmial.com' }).full; // 'Sample.Name+Tag@gmail.com' // 4. 平局不取胜 Mailcheck.run({ email: 'person@cat.com', domains: ['bat.com', 'hat.com'], secondLevelDomains: [] }); // undefined

完整测试入口

npm ci --ignore-scripts --no-audit --no-fund npx --no-install playwright install chromium firefox webkit # 浏览器测试依赖 npm run test:ci # 构建检查 + 全部单元/回归/类型/打包/浏览器测试

各单项命令(npm test、npm run test:types、npm run test:package、npm run test:e2e、npm run test:release)的职责与 Node 版本要求(Node 20.19+)详见 README.md。

七、总结

Mailcheck 2.0.0-beta.1 是一次"正确性优先"的改版:通过 1,438 个 IANA 后缀的离线快照守住现代真实后缀、以平局弃权消除列表顺序依赖、以"精确名字 + 唯一全域名"规则约束补全,把误报率压到最低;同时用随包 TypeScript 类型完整覆盖五种消费形态,却不新增任何运行时 API。如果你正在用 Mailcheck 做表单邮箱纠错,升级前只需重点核对第五节列出的四条行为变化(尤其是gmail.co这类"宁可漏报"的新策略),其余调用代码可以原样迁移。

  • 开发工具

【免费下载链接】mailcheck

Reduce misspelled email addresses in your web apps.

项目地址:https://gitcode.com/gh_mirrors/ma/mailcheck
点击查看免费下载

相关推荐

上一篇:3分钟上手:用G-Helper彻底解放你的华硕笔记本性能
下一篇:Stitched Full-Page Capture:用拼接式视口截图修复懒加载页面的整页截图(Skills 实战指南)

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询