ajv-formats icon indicating copy to clipboard operation
ajv-formats copied to clipboard

email format doesn't handle internationalized email

Open quantmode opened this issue 2 years ago • 1 comments

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.

quantmode avatar May 09 '22 15:05 quantmode

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

quantmode avatar May 09 '22 16:05 quantmode

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
коля@пример.рф

image

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) image

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

AMorgaut avatar Nov 04 '22 16:11 AMorgaut

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.

epoberezkin avatar Nov 04 '22 23:11 epoberezkin

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);
}    

AMorgaut avatar Dec 12 '22 17:12 AMorgaut