Mailcheck 2.0: typo suggestions for email fields, with a deliberate habit of saying nothing
Reduce misspelled email addresses in your web apps.
At a glance
- What is it?
- Mailcheck is a small JavaScript library that suggests a likely email domain after a typo. Version 2.0 is in beta, ships TypeScript declarations and no runtime dependencies, and abstains whenever a suggestion would be a guess.
- Who is it for?
- Adopt Mailcheck if you control a form's front end and want a cheap, offline nudge on the email field: it has no runtime dependencies, makes no network requests, and returns a suggestion object you can render as text. Do not adopt it if you need to know whether an address exists, accepts mail, or belongs to a person, and do not use it to block submission.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 15 days ago.
- What is it written in?
- Mainly JavaScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The problem Mailcheck solves, and the one it refuses to
People mistype domains. They write gmial.con, or they stop at gmail and never finish the ending. Mailcheck looks at the domain portion of an address and proposes a likely correction, so a form can ask "Did you mean [email protected]?" before the person moves on. The README frames the scope tightly: Mailcheck is a typo suggester, not an email validator or a deliverability check. That sentence is the whole design contract. It does not prove an address exists, accepts mail, or belongs to a person.
The audience is front-end developers and anyone maintaining a signup, checkout, or newsletter form where a wrong domain costs a support ticket or a lost confirmation email. It is a browser-first library with an optional jQuery plugin, and it also runs under Node and TypeScript. The repository is not archived, and the last push was on 2026-09-15, so the code is current. The npm package metadata still lists version 1.1.2, while the releases list carries a 2.0.0-beta.2 tag dated 2026-09-14. That gap is worth knowing about before you install.
How the matching works: distance, configured lists, and abstention
Mailcheck splits the address into a local part and a domain, then compares the domain against configured lists: domains, secondLevelDomains, and topLevelDomains. A distance function scores how close the typed domain is to each candidate. The default is a Sift4-style distance, exposed as Mailcheck.sift4Distance, and you can supply your own distanceFunction. The lower-level Mailcheck.suggest() takes the correction lists and the distance function explicitly and returns a suggestion object or false.
The interesting part is what it declines to do. Recognized modern endings such as .ai, .io, .app, and .co are not rewritten merely because another ending is close, so [email protected] gets no suggestion because .co is real. A missing ending is completed only from one exact full-domain target already in the domains list, which is how sample@gmail becomes [email protected]. Partial names, unknown domains, malformed layouts, Unicode and punycode domains, and ambiguous matches all receive no suggestion. Equally close candidates produce nothing rather than depending on list order, and a threshold of 0 means exact matches only.
Two smaller behaviours matter in practice. Local-part case and repeated literal percent signs are preserved, so the library does not quietly normalize what the person typed. And Mailcheck does not alter the field value at all: it returns a suggestion and leaves the decision to the user. The README repeats that instruction twice, once in the API section and once in the safety section.
Installing Mailcheck and wiring a first blur handler
The README gives two install paths. For a bundler or Node, install from npm. For a plain page, load the browser build before calling Mailcheck.run.
npm install mailcheckThe browser route expects a script tag pointing at the minified build. In both cases the call site is the same, and the README's example runs on the blur event of an email input. Note that the suggestion is written with textContent, not innerHTML, and that the empty callback clears the message when there is nothing to suggest.
<input id="email" type="email" autocomplete="email">
<p id="suggestion" aria-live="polite"></p>
<script src="/path/to/mailcheck.min.js"></script>
<script>
var email = document.getElementById('email');
var output = document.getElementById('suggestion');
email.addEventListener('blur', function () {
Mailcheck.run({
email: email.value,
suggested: function (suggestion) {
output.textContent = 'Did you mean ' + suggestion.full + '?';
},
empty: function () {
output.textContent = '';
}
});
});
</script>If you skip the callbacks, run() returns the suggestion directly, which is the quickest way to see what the library will say for a given address. The returned object has address, domain, and full properties, or it is undefined.
var suggestion = Mailcheck.run({ email: '[email protected]' });
// { address: 'sample', domain: 'gmail.com', full: '[email protected]' }
// or undefined when there is no suggestionFor TypeScript, the package ships its own declarations, so no separate @types/mailcheck package is needed. The README's ESM example imports the default export and the Suggestion type, and notes that the default import relies on CommonJS interoperability, supported by Node ESM and TypeScript with esModuleInterop. CommonJS TypeScript users are told to use import Mailcheck = require('mailcheck').
Customizing the domain lists without breaking the defaults
The defaults cover common consumer providers, and the README states that provider defaults include Proton, HEY, Fastmail, and Tuta. If your users are on a corporate domain, you will want your own entries. There are two ways, and they behave differently, which is the kind of detail that bites during a refactor.
Passing domains, secondLevelDomains, or topLevelDomains to run() replaces the corresponding default list. Pushing onto Mailcheck.defaultDomains, Mailcheck.defaultSecondLevelDomains, or Mailcheck.defaultTopLevelDomains extends the defaults instead. The README asks for lowercase lists in both cases.
Mailcheck.run({
email: '[email protected]',
domains: ['acme.com', 'example.org'],
secondLevelDomains: ['acme'],
topLevelDomains: ['com', 'org']
});Mailcheck.defaultDomains.push('acme.com');
Mailcheck.defaultSecondLevelDomains.push('acme');
Mailcheck.defaultTopLevelDomains.push('org');One asymmetry is easy to misread. The public topLevelDomains list holds correction targets, but Mailcheck's internal recognition of real domain endings is not another option you can configure. So you cannot widen or narrow which endings count as already valid by editing that list. If your product deals in newer endings, that behaviour is fixed in the library, not in your config.
Where Mailcheck is the wrong tool
The honest limitation is the one the README states first: it does not prove an address exists, accepts mail, or belongs to a person. If your requirement is deliverability, you need a verification service that performs SMTP or API checks, and Mailcheck will not substitute for it. It also makes no network requests and has no runtime dependencies, which is a strength for privacy and latency but means it can never know anything beyond its configured lists.
Abstention cuts both ways. [email protected] gets no suggestion because .co is real, even if the person meant .com. Unknown domains get nothing. Ambiguous matches get nothing. If your users are spread across many small or regional domains, the suggestion rate will be low, and that is by design rather than a bug to file. The alternative is a library that guesses, which is how you end up telling someone their correct address is wrong.
The safety note is also a limitation in disguise. run() retains the legacy encodeEmail() behavior, and the README says plainly that this encoding is not a general HTML sanitizer. If you render suggestions with innerHTML, you have a problem Mailcheck does not solve for you. Use textContent, jQuery .text(), or your framework's escaped text rendering. Finally, the version situation deserves a look: the package.json in the repository lists version 1.1.2 while the releases list shows v2.0.0-beta.2 dated 2026-09-14, so confirm which line your install actually resolves to before you depend on the 2.0 behaviours described above.
Mailcheck against server-side email verification
The real alternative is not another client-side typo library. It is a server-side verification API that checks syntax, domain records, and whether the mailbox accepts mail. The difference in approach is fundamental: Mailcheck runs entirely in the page, compares a string against lists you control, and never leaves the browser. A verification service sends the address somewhere, asks a remote system, and returns a verdict.
That means the two answer different questions. Mailcheck answers "does this look like a typo of a domain we know?" A verification service answers "does this mailbox exist right now?" The first is instant, free of network cost, and works offline; the second can be wrong anyway, because catch-all domains and greylisting exist, and it puts an address in front of a third party. If you need both, they compose: use Mailcheck on blur to catch obvious typos before submission, and run verification after submission. What you should not do is treat a Mailcheck suggestion as a validation failure and block the form, which the README explicitly warns against.
Maintenance, the beta line, and the MIT licence
The repository is not archived and the last push was on 2026-09-15, so this is not an abandoned project. The release history is uneven, though: 1.1.0 in 2014, 1.1.2 in 2016, then nothing until v2.0.0-beta.2 on 2026-09-14. That is a decade-long gap between the stable line and the rewrite, and the current 2.0 release is a beta. The repository still carries README-1.x.md alongside README.md, which tells you the maintainers expect people to be on both lines for a while.
Upgrade cost depends on which line you are on. The README says the established JavaScript API remains available in 2.0: the same methods, options, callbacks, return values, browser global, and jQuery plugin. That is a compatibility promise, not a guarantee, and the behaviour changes listed for 2.0 (modern endings not rewritten, provider defaults, abstention on equally close candidates) are exactly the kind of thing that can alter what your form displays. Test against your own address corpus.
The licence is MIT, declared in the repository's LICENSE file and in the package metadata. MIT is permissive and imposes no copyleft obligation on your application, but this is a description of the licence text, not legal advice. If your organisation has rules about bundled third-party code, route it through whoever handles that. The build and test scripts are documented in the README, including npm ci --ignore-scripts --no-audit --no-fund, a Playwright browser install, and npm run test:ci, which chains the build check, core tests, type tests, package test, and end-to-end tests.
Editorial conclusion
Adopt Mailcheck if you control a form's front end and want a cheap, offline nudge on the email field: it has no runtime dependencies, makes no network requests, and returns a suggestion object you can render as text. Do not adopt it if you need to know whether an address exists, accepts mail, or belongs to a person, and do not use it to block submission. Before shipping, verify how it behaves on your own domain list by calling Mailcheck.run with the email option and reading the returned object or undefined, and check whether your build pulls the v2.0.0-beta.2 release or the older 1.1.2 line.
Frequently asked questions
What is Mailcheck?
It is a small JavaScript library, with an optional jQuery plugin, that suggests a likely email domain when someone makes a typo, for example turning [email protected] into [email protected]. The README describes it as a typo suggester, not an email validator or a deliverability check.
Does Mailcheck tell me whether an email address is fake?
No. The README states that Mailcheck does not prove that an address exists, accepts mail, or belongs to a person. It only compares the typed domain against configured lists and suggests a correction when it is confident.
How do I install Mailcheck?
The README gives two routes: npm install mailcheck for a bundler or Node, or load the browser build with a script tag before calling Mailcheck.run. The package has no runtime dependencies and makes no network requests.
Can I replace the default domain lists in Mailcheck?
Yes. Passing domains, secondLevelDomains, or topLevelDomains to run() replaces the corresponding defaults, while pushing onto Mailcheck.defaultDomains, Mailcheck.defaultSecondLevelDomains, or Mailcheck.defaultTopLevelDomains extends them. The README asks for lowercase lists.
Does Mailcheck change the email field value automatically?
No. The README says Mailcheck does not alter the field value and that you should show a suggestion rather than silently replace an address or block someone from continuing. It also warns against rendering suggestions with innerHTML.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/mailcheck-mailcheck)