ajv-formats
ajv-formats copied to clipboard
email format doesn't handle internationalized email
The regex for email format used by the format validation is:
/^[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/i
This doesn't handle internationalized email addresses, e.g. those with unicode characters in the user name.
I've verified that adding the unicode letter designator \p{L} to the user name component allows internationalized user names:
/^[\p{L}a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[\p{L}a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/iu
I confirm the initial regexp doesn't validate many international emails
I extracted those ones from wikipedia for testing
- https://en.wikipedia.org/wiki/Email_address
- https://en.wikipedia.org/wiki/International_email
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
test/[email protected]
admin@mailserver1
[email protected]
" "@example.org
"john..doe"@example.org
[email protected]
"very.(),:;<>[]\".VERY.\"very@\\ \"very\".unusual"@strange.example.com
user%[email protected]
[email protected]
postmaster@[123.123.123.123]
postmaster@[IPv6:2001:0db8:85a3:0000:0000:8a2e:0370:7334]
[email protected]
[email protected]
user+mailbox/[email protected]
!#$%&'*+-/=?^_`.{|}[email protected]
"Abc@def"@example.com
"Fred\ Bloggs"@example.com
"Joe.\\Blow"@example.com
用户@例子.广告
ಬೆಂಬಲ@ಡೇಟಾಮೇಲ್.ಭಾರತ
अजय@डाटा.भारत
квіточка@пошта.укр
χρήστης@παράδειγμα.ελ
Dörte@Sörensen.example.com
коля@пример.рф
When trying with the proposed evolution, it didn't work for me on chrome
My guess is that it comes from this limitation (didn't test on node versions)
When tested on the listed invalid email adresses
Abc.example.com
A@b@[email protected]
a"b(c)d,e:f;g<h>i[j\k][email protected]
just"not"[email protected]
this is"not\[email protected]
this\ still\"not\\[email protected]
1234567890123456789012345678901234567890123456789012345678901234+x@example.com
i_like_underscore@but_its_not_allowed_in_this_part.example.com
QA[icon]CHOCOLATE[icon]@test.com
That one was validated while it shouldn't have
- 1234567890123456789012345678901234567890123456789012345678901234+x@example.com (local-part is longer than 64 characters)
Note that some said valid email adresses are not really expected as valid in some contexts like emlail validation for account creation on an internet website. Local email adresses are usually not meant to be acceptable in that context...
I have a concern regarding regexp based validation for emails To me, one of the key advantage of setting a "format" constraint over a simple "regexp" constraint on string is to be able to call dedicated, more advanced validators like https://github.com/mfbx9da4/deep-email-validator
email format is not supposed to do work for international emails, there is an idn-email format available via this package: https://github.com/luzlab/ajv-formats-draft2019
My recommendation is not to rely on formats to validate emails, and only use them as metadata - and do the actual validation in the application, to the level that is required by the application. That matches JSON-Schema recommendation.
Thanks for the link
My recommendation is not to rely on formats to validate emails, (...) and do the actual validation in the application, to the level that is required by the application.
I must say I do totally agree I actually tested the integration of an email dedicated validator (https://www.npmjs.com/package/deep-email-validator) but wanted it to be called by AJV wherever it meets "format: email" the specification, and more specifically from an open api request validator
I must say I was kind of upset by the fact it required to add "$async: true" in the specification to be usable, which is really unfriendly if not quite complicated in some situations like when managing open api files (cf: https://ajv.js.org/guide/async-validation.html)
import Ajv from 'ajv';
import addFormats from "ajv-formats";
import { validate } from "deep-email-validator";
async function validateEmail(email) {
const result = await validate({ email, validateSMTP: false });
if (result.valid) {
return true;
}
console.error("Deep Email Error", result.reason, result.validators[result.reason].reason);
return false;
}
const ajv = new Ajv({ formats: {
'email' : { validate: validateEmail, async: true }
} });
addFormats(ajv);
try {
/* -------------------------------------------- */
const valid = await ajv.validate(
{ type: 'string', format: 'email', $async: true },
"[email protected]"
);
/* -------------------------------------------- */
if (valid) {
console.info('OK AJV email');
} else {
console.error(ajv.errors)
}
} catch (error) {
console.error('catch', error, error.errors);
}