Comment valider une adresse e-mail à l'aide d'une expression régulière?

3316

Au fil des ans, j'ai lentement développé une expression régulière qui valide correctement la plupart des adresses e-mail, en supposant qu'elles n'utilisent pas d'adresse IP comme partie serveur.

Je l'utilise dans plusieurs programmes PHP, et cela fonctionne la plupart du temps. Cependant, de temps en temps, je suis contacté par quelqu'un qui a des problèmes avec un site qui l'utilise, et je dois finir par faire quelques ajustements (plus récemment, j'ai réalisé que je n'autorisais pas les TLD à 4 caractères).

Quelle est la meilleure expression régulière que vous avez ou avez vue pour valider les e-mails?

J'ai vu plusieurs solutions qui utilisent des fonctions qui utilisent plusieurs expressions plus courtes, mais je préfère avoir une longue expression complexe dans une fonction simple au lieu de plusieurs expressions courtes dans une fonction plus complexe.

acrosman
la source
5
L'expression régulière qui peut valider qu'un IDNA est correctement formaté ne tient pas dans stackexchange. (les règles de canonisation étaient vraiment tortueuses et particulièrement inadaptées au traitement des regex)
Jasen
Les expressions régulières peuvent être variables, car dans certains cas, une messagerie électronique peut contenir un espace et, à d'autres moments, elle ne peut contenir aucun espace.
Ṃųỻịgǻňạcểơửṩ

Réponses:

2440

Le regex entièrement conforme à la RFC 822 est inefficace et obscur en raison de sa longueur. Heureusement, la RFC 822 a été remplacée deux fois et la spécification actuelle pour les adresses e-mail est la RFC 5322 . La RFC 5322 conduit à une expression régulière qui peut être comprise si elle est étudiée pendant quelques minutes et est suffisamment efficace pour une utilisation réelle.

Une expression régulière conforme à la RFC 5322 se trouve en haut de la page sur http://emailregex.com/ mais utilise le modèle d'adresse IP flottant sur Internet avec un bogue qui autorise 00toutes les valeurs décimales d'octets non signés dans un adresse délimitée par des points, ce qui est illégal. Le reste semble cohérent avec la grammaire RFC 5322 et passe plusieurs tests en utilisant grep -Po, y compris les cas, les noms de domaine, les adresses IP, les mauvais et les noms de compte avec et sans guillemets.

En corrigeant le 00bogue dans le modèle IP, nous obtenons un regex fonctionnel et assez rapide. (Grattez la version rendue, pas la démarque, pour le code réel.)

(?: [a-z0-9! # $% & '* + / =? ^ _ `{|} ~ -] + (?: \. [a-z0-9! # $% &' * + / =? ^ _ `{|} ~ -] +) * |" (?: [\ x01- \ x08 \ x0b \ x0c \ x0e- \ x1f \ x21 \ x23- \ x5b \ x5d- \ x7f] | \\ [\ x01- \ x09 \ x0b \ x0c \ x0e- \ x7f]) * ") @ (?: (?: [a-z0-9] (?: [a-z0-9 -] * [a-z0 -9])? \.) + [A-z0-9] (?: [A-z0-9 -] * [a-z0-9])? | \ [(? :(? :( 2 (5 [0-5] | [0-4] [0-9]) | 1 [0-9] [0-9] | [1-9]? [0-9])) \.) {3} ( ? :( 2 (5 [0-5] | [0-4] [0-9]) | 1 [0-9] [0-9] | [1-9]? [0-9]) | [ a-z0-9 -] * [a-z0-9]: (?: [\ x01- \ x08 \ x0b \ x0c \ x0e- \ x1f \ x21- \ x5a \ x53- \ x7f] | \\ [\ x01- \ x09 \ x0b \ x0c \ x0e- \ x7f]) +) \])

ou:

(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])

Voici le schéma de la machine à états finis pour l'expression rationnelle ci-dessus qui est plus claire que l'expression rationnelle elle-même entrez la description de l'image ici

Les modèles plus sophistiqués en Perl et PCRE (bibliothèque d'expression régulière utilisée par exemple en PHP) peuvent correctement analyser RFC 5322 sans accroc . Python et C # peuvent également le faire, mais ils utilisent une syntaxe différente de celles des deux premiers. Cependant, si vous êtes obligé d'utiliser l'un des nombreux langages de correspondance de modèles moins puissants, il est préférable d'utiliser un véritable analyseur.

Il est également important de comprendre que sa validation par le RFC ne vous dit absolument rien si cette adresse existe réellement sur le domaine fourni, ou si la personne qui saisit l'adresse est son véritable propriétaire. Les gens inscrivent les autres aux listes de diffusion de cette façon tout le temps. Correction qui nécessite un type de validation plus sophistiqué qui implique d'envoyer à cette adresse un message qui comprend un jeton de confirmation destiné à être entré sur la même page Web que l'adresse.

Les jetons de confirmation sont le seul moyen de savoir que vous avez obtenu l'adresse de la personne qui l'a saisie. C'est pourquoi la plupart des listes de diffusion utilisent désormais ce mécanisme pour confirmer les inscriptions. Après tout, n'importe qui peut réprimer [email protected], et cela sera même analysé comme légal, mais ce n'est probablement pas la personne à l'autre bout.

Pour PHP, vous ne devez pas utiliser le modèle donné dans Valider une adresse e-mail avec PHP, la bonne façon dont je cite:

Il existe un certain danger que l'utilisation courante et le codage bâclé répandu établissent une norme de facto pour les adresses de messagerie qui est plus restrictive que la norme formelle enregistrée.

Ce n'est pas mieux que tous les autres modèles non RFC. Il n'est même pas assez intelligent pour gérer même le RFC 822 , encore moins le RFC 5322. Celui-ci cependant.

Si vous voulez devenir fantaisiste et pédant, implémentez un moteur d'état complet . Une expression régulière ne peut agir que comme un filtre rudimentaire. Le problème avec les expressions régulières est que dire à quelqu'un que son adresse e-mail parfaitement valide n'est pas valide (un faux positif) parce que votre expression régulière ne peut pas la gérer est simplement grossier et impoli du point de vue de l'utilisateur. Un moteur d'état à cet effet peut à la fois valider et même corriger les adresses électroniques qui seraient autrement considérées comme non valides car il démonte l'adresse électronique selon chaque RFC. Cela permet une expérience potentiellement plus agréable, comme

L'adresse e-mail spécifiée «myemail @ address, com» n'est pas valide. Voulez-vous dire '[email protected]'?

Voir aussi Validation des adresses e-mail , y compris les commentaires. Ou Comparaison d'adresses électroniques validant des expressions régulières .

Visualisation des expressions régulières

Démo Debuggex

bortzmeyer
la source
180
Vous avez dit "Il n'y a pas de bonne expression régulière." Est-ce général ou spécifique à la validation de l'adresse e-mail?
Tomalak
37
@Tomalak: uniquement pour les adresses e-mail. Comme l'a dit Bortzmeyer, le RFC est extrêmement compliqué
Luk
37
L'article de revue Linux que vous mentionnez est en fait faux à plusieurs égards. En particulier, Lovell n'a clairement pas lu les errata de la RFC3696 et répète certaines des erreurs dans la version publiée de la RFC. Plus ici: dominicsayers.com/isemail
Dominic Sayers
9
Jeff Atwood a une belle expression régulière dans ce billet de blog pour valider toutes les adresses e-mail valides: codinghorror.com/blog/2005/02/regex-use-vs-regex-abuse.html
CMircea
5
Notez que la spécification HTML5 actuelle comprend une expression régulière et un ABNF pour la validation des entrées de type e-mail qui est délibérément plus restrictive que les RFC d'origine.
Synchro
747

Vous ne devez pas utiliser d'expressions régulières pour valider les adresses e-mail.

À la place, utilisez la classe MailAddress , comme ceci:

try {
    address = new MailAddress(address).Address;
} catch(FormatException) {
    // address is invalid
}

La MailAddressclasse utilise un analyseur BNF pour valider l'adresse en totale conformité avec RFC822.

Si vous envisagez d'utiliser le MailAddresspour valider l'adresse de messagerie, sachez que cette approche accepte également la partie nom complet de l'adresse de messagerie et que ce n'est peut-être pas exactement ce que vous souhaitez obtenir. Par exemple, il accepte ces chaînes comme adresses e-mail valides:

Dans certains de ces cas, seule la dernière partie des chaînes est analysée en tant qu'adresse; le reste avant c'est le nom d'affichage. Pour obtenir une adresse e-mail standard sans aucun nom d'affichage, vous pouvez vérifier l'adresse normalisée par rapport à votre chaîne d'origine.

bool isValid = false;

try
{
    MailAddress address = new MailAddress(emailAddress);
    isValid = (address.Address == emailAddress);
    // or
    // isValid = string.IsNullOrEmpty(address.DisplayName);
}
catch (FormatException)
{
    // address is invalid
}

De plus, une adresse ayant un point à la fin, comme, user@company.est également acceptée par MailAddress.

Si vous voulez vraiment utiliser une expression régulière, la voici :

(?: (?: \ r \ n)? [\ t]) * (?: (?: (?: [^ () <> @,;: \\ ". \ [\] \ 000- \ 031 ] + (?: (?: (?: \ r \ n)? [\ t]
) + | \ Z | (? = [\ ["() <> @,;: \\". \ [\]])) | "(?: [^ \" \ R \\] | \\. | (?: (?: \ r \ n)? [\ t])) * "(? :( ?:
\ r \ n)? [\ t]) *) (?: \. (?: (?: \ r \ n)? [\ t]) * (?: [^ () <> @,;: \ \ ". \ [\] \ 000- \ 031] + (? :(? :(
?: \ r \ n)? [\ t]) + | \ Z | (? = [\ ["() <> @,;: \\". \ [\]])) | "(?: [ ^ \ "\ r \\] | \\. | (?: (?: \ r \ n)? [ 
\ t])) * "(?: (?: \ r \ n)? [\ t]) *)) * @ (?: (?: \ r \ n)? [\ t]) * (?: [^ () <> @,;: \\ ". \ [\] \ 000- \ 0
31] + (?: (?: (?: \ R \ n)? [\ T]) + | \ Z | (? = [\ ["() <> @,;: \\". \ [\ ]])) | \ [([^ \ [\] \ r \\] | \\.) * \
] (?: (?: \ r \ n)? [\ t]) *) (?: \. (?: (?: \ r \ n)? [\ t]) * (?: [^ () <> @,;: \\ ". \ [\] \ 000- \ 031] +
(?: (?: (?: \ r \ n)? [\ t]) + | \ Z | (? = [\ ["() <> @,;: \\". \ [\]]) ) | \ [([^ \ [\] \ r \\] | \\.) * \] (?:
(?: \ r \ n)? [\ t]) *)) * | (?: [^ () <> @,;: \\ ". \ [\] \ 000- \ 031] + (?: (?: (?: \ r \ n)? [\ t]) + | \ Z
| (? = [\ ["() <> @,;: \\". \ [\]])) | "(?: [^ \" \ r \\] | \\. | (? :( ?: \ r \ n)? [\ t])) * "(?: (?: \ r \ n)
? [\ t]) *) * \ <(?: (?: \ r \ n)? [\ t]) * (?: @ (?: [^ () <> @,;: \\ ". \ [\] \ 000- \ 031] + (?: (?: (?: \
r \ n)? [\ t]) + | \ Z | (? = [\ ["() <> @,;: \\". \ [\]])) | \ [([^ \ [\ ] \ r \\] | \\.) * \] (?: (?: \ r \ n)? [
 \ t]) *) (?: \. (?: (?: \ r \ n)? [\ t]) * (?: [^ () <> @,;: \\ ". \ [\] \ 000- \ 031] + (?: (?: (?: \ R \ n)
? [\ t]) + | \ Z | (? = [\ ["() <> @,;: \\". \ [\]])) | \ [([^ \ [\] \ r \ \] | \\.) * \] (?: (?: \ r \ n)? [\ t]
) *)) * (?:, @ (?: (?: \ r \ n)? [\ t]) * (?: [^ () <> @,;: \\ ". \ [\] \ 000- \ 031] + (?: (?: (?: \ R \ n)? [
 \ t]) + | \ Z | (? = [\ ["() <> @,;: \\". \ [\]])) | \ [([^ \ [\] \ r \\] | \\.) * \] (?: (?: \ r \ n)? [\ t]) *
) (?: \. (?: (?: \ r \ n)? [\ t]) * (?: [^ () <> @,;: \\ ". \ [\] \ 000- \ 031 ] + (?: (?: (?: \ r \ n)? [\ t]
) + | \ Z | (? = [\ ["() <> @,;: \\". \ [\]])) | \ [([^ \ [\] \ R \\] | \\ .) * \] (?: (?: \ r \ n)? [\ t]) *)) *)
*: (?: (?: \ r \ n)? [\ t]) *)? (?: [^ () <> @,;: \\ ". \ [\] \ 000- \ 031] + (?: (?: (?: \ r \ n)? [\ t]) +
| \ Z | (? = [\ ["() <> @,;: \\". \ [\]])) | "(?: [^ \" \ R \\] | \\. | ( ?: (?: \ r \ n)? [\ t])) * "(?: (?: \ r
\ n)? [\ t]) *) (?: \. (?: (?: \ r \ n)? [\ t]) * (?: [^ () <> @,;: \\ " . \ [\] \ 000- \ 031] + (? :(? :(?:
\ r \ n)? [\ t]) + | \ Z | (? = [\ ["() <> @,;: \\". \ [\]])) | "(?: [^ \ "\ r \\] | \\. | (?: (?: \ r \ n)? [\ t
])) * "(?: (?: \ r \ n)? [\ t]) *)) * @ (?: (?: \ r \ n)? [\ t]) * (?: [^ () <> @,;: \\ ". \ [\] \ 000- \ 031
] + (?: (?: (?: \ r \ n)? [\ t]) + | \ Z | (? = [\ ["() <> @,;: \\". \ [\] ])) | \ [([^ \ [\] \ r \\] | \\.) * \] (
?: (?: \ r \ n)? [\ t]) *) (?: \. (?: (?: \ r \ n)? [\ t]) * (?: [^ () <> @,;: \\ ". \ [\] \ 000- \ 031] + (?
: (?: (?: \ r \ n)? [\ t]) + | \ Z | (? = [\ ["() <> @,;: \\". \ [\]])) | \ [([^ \ [\] \ r \\] | \\.) * \] (? :(?
: \ r \ n)? [\ t]) *)) * \> (?: (?: \ r \ n)? [\ t]) *) | (?: [^ () <> @ ,; : \\ ". \ [\] \ 000- \ 031] + (? :(?
: (?: \ r \ n)? [\ t]) + | \ Z | (? = [\ ["() <> @,;: \\". \ [\]])) | "(? : [^ \ "\ r \\] | \\. | (?: (?: \ r \ n)?
[\ t])) * "(?: (?: \ r \ n)? [\ t]) *) *: (?: (?: \ r \ n)? [\ t]) * (?: (?: (?: [^ () <> @,;: \\ ". \ [\] 
\ 000- \ 031] + (?: (?: (?: \ R \ n)? [\ T]) + | \ Z | (? = [\ ["() <> @,;: \\" . \ [\]])) | "(?: [^ \" \ r \\] |
\\. | (?: (?: \ r \ n)? [\ t])) * "(?: (?: \ r \ n)? [\ t]) *) (?: \. (? : (?: \ r \ n)? [\ t]) * (?: [^ () <>

@,;: \\ ". \ [\] \ 000- \ 031] + (?: (?: (?: \ R \ n)? [\ T]) + | \ Z | (? = [\ [ "() <> @,;: \\". \ [\]])) | "
(?: [^ \ "\ r \\] | \\. | (?: (?: \ r \ n)? [\ t])) *" (?: (?: \ r \ n)? [ \ t]) *)) * @ (?: (?: \ r \ n)? [\ t]
) * (?: [^ () <> @,;: \\ ". \ [\] \ 000- \ 031] + (?: (?: (?: \ R \ n)? [\ T]) + | \ Z | (? = [\ ["() <> @,;: \\
". \ [\]])) | \ [([^ \ [\] \ r \\] | \\.) * \] (?: (?: \ r \ n)? [\ t]) * ) (?: \. (?: (?: \ r \ n)? [\ t]) * (?
: [^ () <> @,;: \\ ". \ [\] \ 000- \ 031] + (?: (?: (?: \ R \ n)? [\ T]) + | \ Z | (? = [\ ["() <> @,;: \\". \ [
\]])) | \ [([^ \ [\] \ r \\] | \\.) * \] (?: (?: \ r \ n)? [\ t]) *)) * | (?: [^ () <> @,;: \\ ". \ [\] \ 000-
\ 031] + (?: (?: (?: \ R \ n)? [\ T]) + | \ Z | (? = [\ ["() <> @,;: \\". \ [ \]])) | "(?: [^ \" \ r \\] | \\. | (
?: (?: \ r \ n)? [\ t])) * "(?: (?: \ r \ n)? [\ t]) *) * \ <(?: (?: \ r \ n)? [\ t]) * (?: @ (?: [^ () <> @ ,;
: \\ ". \ [\] \ 000- \ 031] + (?: (?: (?: \ R \ n)? [\ T]) + | \ Z | (? = [\ [" () <> @,;: \\ ". \ [\]])) | \ [([
^ \ [\] \ r \\] | \\.) * \] (?: (?: \ r \ n)? [\ t]) *) (?: \. (?: (?: \ r \ n)? [\ t]) * (?: [^ () <> @,;: \\ "
. \ [\] \ 000- \ 031] + (?: (?: (?: \ R \ n)? [\ T]) + | \ Z | (? = [\ ["() <> @, ;: \\ ". \ [\]])) | \ [([^ \ [\
] \ r \\] | \\.) * \] (?: (?: \ r \ n)? [\ t]) *)) * (?:, @ (?: (?: \ r \ n )? [\ t]) * (?: [^ () <> @,;: \\ ". \
[\] \ 000- \ 031] + (?: (?: (?: \ R \ n)? [\ T]) + | \ Z | (? = [\ ["() <> @,;: \\ ". \ [\]])) | \ [([^ \ [\] \
r \\] | \\.) * \] (?: (?: \ r \ n)? [\ t]) *) (?: \. (?: (?: \ r \ n)? [\ t]) * (?: [^ () <> @,;: \\ ". \ [\] 
\ 000- \ 031] + (?: (?: (?: \ R \ n)? [\ T]) + | \ Z | (? = [\ ["() <> @,;: \\" . \ [\]])) | \ [([^ \ [\] \ r \\]
| \\.) * \] (?: (?: \ r \ n)? [\ t]) *)) *) *: (?: (?: \ r \ n)? [\ t]) * )? (?: [^ () <> @,;: \\ ". \ [\] \ 0
00- \ 031] + (?: (?: (?: \ R \ n)? [\ T]) + | \ Z | (? = [\ ["() <> @,;: \\". \ [\]])) | "(?: [^ \" \ r \\] | \\
. | (?: (?: \ r \ n)? [\ t])) * "(?: (?: \ r \ n)? [\ t]) *) (?: \. (? :( ?: \ r \ n)? [\ t]) * (?: [^ () <> @,
;: \\ ". \ [\] \ 000- \ 031] + (?: (?: (?: \ R \ n)? [\ T]) + | \ Z | (? = [\ [" ( ) <> @,;: \\ ". \ [\]])) |" (?
: [^ \ "\ r \\] | \\. | (?: (?: \ r \ n)? [\ t])) *" (?: (?: \ r \ n)? [\ t ]) *)) * @ (?: (?: \ r \ n)? [\ t]) *
(?: [^ () <> @,;: \\ ". \ [\] \ 000- \ 031] + (?: (?: (?: \ R \ n)? [\ T]) + | \ Z | (? = [\ ["() <> @,;: \\".
\ [\]])) | \ [([^ \ [\] \ r \\] | \\.) * \] (?: (?: \ r \ n)? [\ t]) *) ( ?: \. (?: (?: \ r \ n)? [\ t]) * (?: [
^ () <> @,;: \\ ". \ [\] \ 000- \ 031] + (?: (?: (?: \ R \ n)? [\ T]) + | \ Z | ( ? = [\ ["() <> @,;: \\". \ [\]
])) | \ [([^ \ [\] \ r \\] | \\.) * \] (?: (?: \ r \ n)? [\ t]) *)) * \> ( ?: (?: \ r \ n)? [\ t]) *) (?:, \ s * (
?: (?: [^ () <> @,;: \\ ". \ [\] \ 000- \ 031] + (?: (?: (?: \ R \ n)? [\ T]) + | \ Z | (? = [\ ["() <> @,;: \\
". \ [\]])) |" (?: [^ \ "\ r \\] | \\. | (?: (?: \ r \ n)? [\ t])) *" (? : (?: \ r \ n)? [\ t]) *) (?: \. (? :(
?: \ r \ n)? [\ t]) * (?: [^ () <> @,;: \\ ". \ [\] \ 000- \ 031] + (? :(? :(? : \ r \ n)? [\ t]) + | \ Z | (? = [
\ ["() <> @,;: \\". \ [\]])) | "(?: [^ \" \ r \\] | \\. | (?: (?: \ r \ n)? [\ t])) * "(?: (?: \ r \ n)? [\ t
]) *)) * @ (?: (?: \ r \ n)? [\ t]) * (?: [^ () <> @,;: \\ ". \ [\] \ 000- \ 031] + (?: (?: (?: \ R \ n)? [\ T
]) + | \ Z | (? = [\ ["() <> @,;: \\". \ [\]])) | \ [([^ \ [\] \ R \\] | \ \.) * \] (?: (?: \ r \ n)? [\ t]) *) (?
: \. (?: (?: \ r \ n)? [\ t]) * (?: [^ () <> @,;: \\ ". \ [\] \ 000- \ 031] + ( ?: (?: (?: \ r \ n)? [\ t]) + |
\ Z | (? = [\ ["() <> @,;: \\". \ [\]])) | \ [([^ \ [\] \ R \\] | \\.) * \] (?: (?: \ r \ n)? [\ t]) *)) * | (?:
[^ () <> @,;: \\ ". \ [\] \ 000- \ 031] + (?: (?: (?: \ R \ n)? [\ T]) + | \ Z | (? = [\ ["() <> @,;: \\". \ [\
]])) | "(?: [^ \" \ r \\] | \\. | (?: (?: \ r \ n)? [\ t])) * "(?: (?: \ r \ n)? [\ t]) *) * \ <(?: (?: \ r \ n)
? [\ t]) * (?: @ (?: [^ () <> @,;: \\ ". \ [\] \ 000- \ 031] + (?: (?: (?: \ r \ n)? [\ t]) + | \ Z | (? = [\ ["
() <> @,;: \\ ". \ [\]])) | \ [([^ \ [\] \ r \\] | \\.) * \] (?: (?: \ r \ n)? [\ t]) *) (?: \. (?: (?: \ r \ n)
? [\ t]) * (?: [^ () <> @,;: \\ ". \ [\] \ 000- \ 031] + (?: (?: (?: \ r \ n)? [\ t]) + | \ Z | (? = [\ ["() <>

@,;: \\ ". \ [\]])) | \ [([^ \ [\] \ r \\] | \\.) * \] (?: (?: \ r \ n)? [\ t]) *)) * (?:, @ (?: (?: \ r \ n)? [
 \ t]) * (?: [^ () <> @,;: \\ ". \ [\] \ 000- \ 031] + (?: (?: (?: \ r \ n)? [\ t]) + | \ Z | (? = [\ ["() <> @,
;: \\ ". \ [\]])) | \ [([^ \ [\] \ r \\] | \\.) * \] (?: (?: \ r \ n)? [\ t]) *) (?: \. (?: (?: \ r \ n)? [\ t]
) * (?: [^ () <> @,;: \\ ". \ [\] \ 000- \ 031] + (?: (?: (?: \ R \ n)? [\ T]) + | \ Z | (? = [\ ["() <> @,;: \\
". \ [\]])) | \ [([^ \ [\] \ r \\] | \\.) * \] (?: (?: \ r \ n)? [\ t]) * )) *) *: (?: (?: \ r \ n)? [\ t]) *)?
(?: [^ () <> @,;: \\ ". \ [\] \ 000- \ 031] + (?: (?: (?: \ R \ n)? [\ T]) + | \ Z | (? = [\ ["() <> @,;: \\".
\ [\]])) | "(?: [^ \" \ r \\] | \\. | (?: (?: \ r \ n)? [\ t])) * "(? :( ?: \ r \ n)? [\ t]) *) (?: \. (? :( ?:
\ r \ n)? [\ t]) * (?: [^ () <> @,;: \\ ". \ [\] \ 000- \ 031] + (?: (?: (?: \ r \ n)? [\ t]) + | \ Z | (? = [\ [
"() <> @,;: \\". \ [\]])) | "(?: [^ \" \ r \\] | \\. | (?: (?: \ r \ n) ? [\ t])) * "(?: (?: \ r \ n)? [\ t])
*)) * @ (?: (?: \ r \ n)? [\ t]) * (?: [^ () <> @,;: \\ ". \ [\] \ 000- \ 031] + (?: (?: (?: \ r \ n)? [\ t])
+ | \ Z | (? = [\ ["() <> @,;: \\". \ [\]])) | \ [([^ \ [\] \ R \\] | \\. ) * \] (?: (?: \ r \ n)? [\ t]) *) (?: \
. (?: (?: \ r \ n)? [\ t]) * (?: [^ () <> @,;: \\ ". \ [\] \ 000- \ 031] + (?: (?: (?: \ r \ n)? [\ t]) + | \ Z
| (? = [\ ["() <> @,;: \\". \ [\]])) | \ [([^ \ [\] \ r \\] | \\.) * \] (?: (?: \ r \ n)? [\ t]) *)) * \> (? :(
?: \ r \ n)? [\ t]) *)) *)?; \ s *)
SLaks
la source
26
Vous constaterez que la classe MailAddress dans .NET 4.0 est bien meilleure pour valider les adresses électroniques que dans les versions précédentes. J'y ai apporté des améliorations importantes.
Jeff Tucker
7
Je pense que ça ne marche pas ... pour des identifiants plus simples. a @ b ne valide pas. [email protected] ne correspond que jusqu'à ar @ b, le .com ne correspond pas. Cependant, quelque chose comme "Je suis moi" @ [10.10.10.10] fonctionne! :)
Raze
5
Soyez averti que ces validateurs d'expressions rationnelles conformes à la RFC laisseront passer de nombreuses adresses e-mail que vous ne voudriez probablement pas accepter, comme "une <body / onload = alert (' lol.com?'+document.cookies ) @aa> "qui est une adresse e-mail valide dans Email :: Valid de perl (qui utilise cette énorme expression régulière), et qui peut être exploitée pour XSS rt.cpan.org/Public/Bug/Display.html?id=75650
Matthew Lock
9
@MatthewLock: Ce n'est pas pire que [email protected]. Vous ne devez pas vous fier à la validation des e-mails pour empêcher XSS.
SLaks
10
@MatthewLock: Non. Vous devez échapper aux requêtes SQL (ou, mieux encore, utiliser des paramètres). La désinfection n'est pas une défense appropriée.
SLaks
536

Cette question est souvent posée, mais je pense que vous devriez prendre du recul et vous demander pourquoi vous souhaitez valider syntaxiquement les adresses e-mail? Quel est vraiment l'avantage?

  • Il n'attrapera pas les fautes de frappe courantes.
  • Cela n'empêche pas les gens d'entrer des adresses e-mail invalides ou inventées, ou d'entrer l'adresse de quelqu'un d'autre.

Si vous souhaitez valider l'exactitude d'un e-mail, vous n'avez pas d'autre choix que d'envoyer un e-mail de confirmation et de demander à l'utilisateur d'y répondre. Dans de nombreux cas , vous devrez avoir à envoyer un mail de confirmation de toute façon pour des raisons de sécurité ou pour des raisons d' ordre éthique ( de sorte que vous ne pouvez pas quelqu'un signe par exemple à un service contre leur gré).

JacquesB
la source
92
Il vaut peut-être la peine de vérifier qu'ils ont entré quelque chose @ quelque chose dans le champ lors d'une validation côté client juste pour détecter des erreurs simples - mais en général, vous avez raison.
Martin Beckett
8
Martin, je vous ai donné un +1, pour lire plus tard que foobar @ dk est un e-mail valide. Ce ne serait pas joli, mais si vous voulez être à la fois conforme à la RFC ET faire preuve de bon sens, vous devez détecter des cas comme celui-ci et demander à l'utilisateur de confirmer que c'est correct.
philfreo
106
@olavk: si quelqu'un entre une faute de frappe (par exemple:) me@hotmail, il est évident qu'il ne recevra pas votre e-mail de confirmation, et où est-il? Ils ne sont plus sur votre site et se demandent pourquoi ils n'ont pas pu s'inscrire. En fait non, ils ne le sont pas - ils vous ont complètement oublié. Cependant, si vous pouviez simplement faire un test de santé mentale de base avec une expression régulière alors qu'ils sont toujours avec vous, alors ils peuvent détecter cette erreur immédiatement et vous avez un utilisateur heureux.
nickf
5
@JacquesB: Vous faites un excellent point. Ce n'est pas parce qu'il passe par le RFC que c'est vraiment l'adresse de cet utilisateur. Sinon, toutes ces [email protected]adresses indiquent un commandant en chef très netbusy. :)
tchrist
39
Il ne doit pas nécessairement être noir ou blanc. Si l'e-mail semble incorrect, faites-le savoir à l'utilisateur. Si l'utilisateur souhaite continuer, laissez-le. Ne forcez pas l'utilisateur à se conformer à votre regex, utilisez plutôt regex comme outil pour aider l'utilisateur à savoir qu'il pourrait y avoir une erreur.
ninjaneer
354

Tout dépend de la précision que vous souhaitez avoir. Pour mes besoins, où j'essaie simplement de garder des choses comme bob @ aol.com(espaces dans les e-mails) ou steve(pas de domaine du tout) ou mary@aolcom(pas de période avant .com), j'utilise

/^\S+@\S+\.\S+$/

Bien sûr, cela correspondra à des choses qui ne sont pas des adresses e-mail valides, mais il s'agit d'obtenir des erreurs simples courantes.

Il y a un certain nombre de changements qui peuvent être apportés à cette expression régulière (et certains sont dans les commentaires de cette réponse), mais c'est simple et facile à comprendre, et c'est une bonne première tentative.

Andy Lester
la source
6
Il ne correspond pas à foobar @ dk qui est une adresse e-mail valide et fonctionnelle (bien que la plupart des serveurs de messagerie ne l'accepteront probablement pas ou ajouteront quelque
chose.com
3
Oui, il sera. Je vous suggère de l'essayer vous-même. $ perl -le'print q{[email protected]} = ~ /^\S+@\S+\.\S+$/? q {Y}: q {N} '
Andy Lester
7
@Richard: .est inclus dans \S.
David Thornley
43
JJJ: Oui, cela correspondra à beaucoup de merde. Cela correspondra à & $ * # $ (@ $ 0 (%)) $ #.) & *) (* $ Aussi. Pour moi, je suis plus préoccupé par la capture de la faute de frappe bizarre mary@aolcomque comme je suis une ordure complète . YMMV.
Andy Lester
5
Juste pour contrôler les @signes: /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/ jsfiddle.net/b9chris/mXB96
Chris Moschini
338

Cela dépend de ce que vous entendez par mieux: si vous parlez d'attraper chaque adresse e-mail valide, utilisez ce qui suit:

(?:(?:\r\n)?[ \t])*(?:(?:(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t]
)+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:
\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(
?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ 
\t]))*"(?:(?:\r\n)?[ \t])*))*@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\0
31]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\
](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+
(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:
(?:\r\n)?[ \t])*))*|(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z
|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)
?[ \t])*)*\<(?:(?:\r\n)?[ \t])*(?:@(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\
r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[
 \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)
?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t]
)*))*(?:,@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[
 \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*
)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t]
)+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*)
*:(?:(?:\r\n)?[ \t])*)?(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+
|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r
\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:
\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t
]))*"(?:(?:\r\n)?[ \t])*))*@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031
]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](
?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?
:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?
:\r\n)?[ \t])*))*\>(?:(?:\r\n)?[ \t])*)|(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?
:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?
[ \t]))*"(?:(?:\r\n)?[ \t])*)*:(?:(?:\r\n)?[ \t])*(?:(?:(?:[^()<>@,;:\\".\[\] 
\000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|
\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>
@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"
(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*))*@(?:(?:\r\n)?[ \t]
)*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\
".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?
:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[
\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*|(?:[^()<>@,;:\\".\[\] \000-
\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(
?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)*\<(?:(?:\r\n)?[ \t])*(?:@(?:[^()<>@,;
:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([
^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\"
.\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\
]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*(?:,@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\
[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\
r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] 
\000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]
|\\.)*\](?:(?:\r\n)?[ \t])*))*)*:(?:(?:\r\n)?[ \t])*)?(?:[^()<>@,;:\\".\[\] \0
00-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\
.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,
;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?
:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*))*@(?:(?:\r\n)?[ \t])*
(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".
\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[
^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]
]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*\>(?:(?:\r\n)?[ \t])*)(?:,\s*(
?:(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\
".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)(?:\.(?:(
?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[
\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t
])*))*@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t
])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?
:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|
\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*|(?:
[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\
]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)*\<(?:(?:\r\n)
?[ \t])*(?:@(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["
()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)
?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>
@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*(?:,@(?:(?:\r\n)?[
 \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,
;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t]
)*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\
".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*)*:(?:(?:\r\n)?[ \t])*)?
(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".
\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)(?:\.(?:(?:
\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\[
"()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])
*))*@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])
+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\
.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z
|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*\>(?:(
?:\r\n)?[ \t])*))*)?;\s*)

( http://www.ex-parrot.com/~pdw/Mail-RFC822-Address.html ) Si vous cherchez quelque chose de plus simple mais qui captera la plupart des adresses e-mail valides, essayez quelque chose comme:

"^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$"

EDIT: A partir du lien:

Cette expression régulière ne valide que les adresses dont les commentaires ont été supprimés et remplacés par des espaces (cela est fait par le module).

Bonne personne
la source
10
Il ne correspond pas à toutes les adresses, certaines doivent être transformées en premier. À partir du lien: "Cette expression régulière ne validera que les adresses dont les commentaires ont été supprimés et remplacés par des espaces (cela est fait par le module)."
Chas. Owens
47
Pouvez-vous me donner un exemple de certains email addressqui traversent à tort le second, mais sont capturés par l'expression régulière plus longue?
Lazer
4
Bien que je l'aimais une fois, c'est un validateur RFC 822, pas un RFC 5322 .
tchrist
24
@Lazer in..valid @ example.com serait un exemple simple. Vous n'êtes pas autorisé à avoir deux points non cotés consécutifs dans la partie locale.
Randal Schwartz
5
@Mikhail perl mais vous ne devriez pas vraiment l'utiliser.
Bonne personne du
287

[MISE À JOUR] J'ai rassemblé tout ce que je sais sur la validation des adresses e-mail ici: http://isemail.info , qui non seulement valide mais diagnostique désormais les problèmes avec les adresses e-mail. Je suis d'accord avec de nombreux commentaires ici que la validation n'est qu'une partie de la réponse; voir mon essai à http://isemail.info/about .

is_email () reste, pour autant que je sache, le seul validateur qui vous dira définitivement si une chaîne donnée est une adresse e-mail valide ou non. J'ai téléchargé une nouvelle version sur http://isemail.info/

J'ai rassemblé des cas de test de Cal Henderson, Dave Child, Phil Haack, Doug Lovell, RFC5322 et RFC 3696. 275 adresses de test en tout. J'ai exécuté tous ces tests contre tous les validateurs gratuits que j'ai pu trouver.

J'essaierai de garder cette page à jour pendant que les gens améliorent leurs validateurs. Merci à Cal, Michael, Dave, Paul et Phil pour leur aide et leur coopération dans la compilation de ces tests et les critiques constructives de mon propre validateur .

Les gens doivent être conscients des errata contre RFC 3696 en particulier. Trois des exemples canoniques sont en fait des adresses invalides. Et la longueur maximale d'une adresse est de 254 ou 256 caractères, pas 320.

Dominic Sayers
la source
Ce validateur semble également correct. [... le temps passe ...] Hm, on dirait que c'est juste la RFC 5322, pas 3693 ou des errata.
tchrist
1
Très agréable. Ici, nous obtenons non seulement un bel essai, nous obtenons un testeur de validation ainsi qu'une bibliothèque à télécharger. Bonne réponse!
bgmCoder
Votre validateur ne prend pas en charge le punycode (RFC 3492). name@öäü.at peut être une adresse valide. (cela se traduit par [email protected])
Josef dit Réintégrer Monica
Salut @Josef. Vous devriez essayer de valider[email protected] car ce code concerne la validation, pas l'interprétation. Si vous souhaitez ajouter un traducteur punycode, je suis heureux d'accepter une demande d'extraction sur github.com/dominicsayers/isemail
Dominic Sayers
266

Selon les spécifications HTML5 du W3C :

^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$

Le contexte:

Une adresse e-mail valide est une chaîne qui correspond à la production ABNF […].

Remarque: Cette exigence est une violation volontaire de la RFC 5322 , qui définit une syntaxe pour les adresses de messagerie qui est à la fois trop stricte (avant le caractère «@»), trop vague (après le caractère «@») et trop laxiste ( permettant aux commentaires, aux espaces et aux chaînes de guillemets d'une manière qui n'est pas familière à la plupart des utilisateurs) d'être utiles ici.

L'expression régulière compatible JavaScript et Perl suivante est une implémentation de la définition ci-dessus.

/^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/

Rory O'Kane
la source
12
C'est intéressant. C'est une violation de la RFC, mais volontaire et cela fait du sesne. Exemple réel: gmail ignore les points dans la partie avant @, donc si votre e-mail est [email protected], vous pouvez envoyer des e-mails pour tester. @ Gmail.com ou tester .... @ gmail.com, ces deux adresses sont invalide selon RFC, mais valide dans le monde réel.
valentinas
Je pense que la dernière partie devrait être '+' au lieu de '*': ^ [a-zA-Z0-9.! # $% & '* + / =? ^ _ `{|} ~ -] + @ [a- zA-Z0-9 -] + (?: \. [a-zA-Z0-9 -] +) + $
mmmmmm
7
@mmmmmm john.doe@localhostest valide. Bien sûr, dans une application réelle (c'est-à-dire une communauté), j'aimerais que votre suggestion remplace * par +
rabudde
3
@valentinas En fait, le RFC n'exclut pas ces parties locales, mais elles doivent être citées. "test...."@gmail.comest parfaitement valide selon la RFC et sémantiquement équivalent à [email protected].
Rinke
J'obtiens une erreur en essayant d'envoyer un e-mail en utilisant python via le relais de mon entreprise si j'essaie d'envoyer à une adresse avec un. @ Ou .. @. En fait, c'est également le cas avec un _ @. Je préfère les retirer avant d'envoyer plutôt que de croire que le destinataire le fera.
ndvo
201

C'est facile en Perl 5.10 ou plus récent:

/(?(DEFINE)
   (?<address>         (?&mailbox) | (?&group))
   (?<mailbox>         (?&name_addr) | (?&addr_spec))
   (?<name_addr>       (?&display_name)? (?&angle_addr))
   (?<angle_addr>      (?&CFWS)? < (?&addr_spec) > (?&CFWS)?)
   (?<group>           (?&display_name) : (?:(?&mailbox_list) | (?&CFWS))? ;
                                          (?&CFWS)?)
   (?<display_name>    (?&phrase))
   (?<mailbox_list>    (?&mailbox) (?: , (?&mailbox))*)

   (?<addr_spec>       (?&local_part) \@ (?&domain))
   (?<local_part>      (?&dot_atom) | (?&quoted_string))
   (?<domain>          (?&dot_atom) | (?&domain_literal))
   (?<domain_literal>  (?&CFWS)? \[ (?: (?&FWS)? (?&dcontent))* (?&FWS)?
                                 \] (?&CFWS)?)
   (?<dcontent>        (?&dtext) | (?&quoted_pair))
   (?<dtext>           (?&NO_WS_CTL) | [\x21-\x5a\x5e-\x7e])

   (?<atext>           (?&ALPHA) | (?&DIGIT) | [!#\$%&'*+-/=?^_`{|}~])
   (?<atom>            (?&CFWS)? (?&atext)+ (?&CFWS)?)
   (?<dot_atom>        (?&CFWS)? (?&dot_atom_text) (?&CFWS)?)
   (?<dot_atom_text>   (?&atext)+ (?: \. (?&atext)+)*)

   (?<text>            [\x01-\x09\x0b\x0c\x0e-\x7f])
   (?<quoted_pair>     \\ (?&text))

   (?<qtext>           (?&NO_WS_CTL) | [\x21\x23-\x5b\x5d-\x7e])
   (?<qcontent>        (?&qtext) | (?&quoted_pair))
   (?<quoted_string>   (?&CFWS)? (?&DQUOTE) (?:(?&FWS)? (?&qcontent))*
                        (?&FWS)? (?&DQUOTE) (?&CFWS)?)

   (?<word>            (?&atom) | (?&quoted_string))
   (?<phrase>          (?&word)+)

   # Folding white space
   (?<FWS>             (?: (?&WSP)* (?&CRLF))? (?&WSP)+)
   (?<ctext>           (?&NO_WS_CTL) | [\x21-\x27\x2a-\x5b\x5d-\x7e])
   (?<ccontent>        (?&ctext) | (?&quoted_pair) | (?&comment))
   (?<comment>         \( (?: (?&FWS)? (?&ccontent))* (?&FWS)? \) )
   (?<CFWS>            (?: (?&FWS)? (?&comment))*
                       (?: (?:(?&FWS)? (?&comment)) | (?&FWS)))

   # No whitespace control
   (?<NO_WS_CTL>       [\x01-\x08\x0b\x0c\x0e-\x1f\x7f])

   (?<ALPHA>           [A-Za-z])
   (?<DIGIT>           [0-9])
   (?<CRLF>            \x0d \x0a)
   (?<DQUOTE>          ")
   (?<WSP>             [\x20\x09])
 )

 (?&address)/x
Abigail
la source
20
J'adorerais
4
Je pense que seul un sous-ensemble de la addrspecpartie est vraiment pertinent pour la question. Accepter plus que cela et le transmettre si une autre partie du système qui n'est pas prête à accepter les adresses RFC5822 complètes, c'est comme si la prise de vue était votre propre pied.
dolmen
3
Génial (+1) mais techniquement ce n'est pas une expression régulière bien sûr ... (ce qui serait impossible car la grammaire n'est pas régulière).
Rinke
10
les expressions régulières ont cessé d'être régulières il y a quelque temps. C'est un 'regex' Perl valide!
rjh
4
J'ai mis en place un test pour cette expression régulière sur IDEone: ideone.com/2XFecH Cependant, ce n'est pas juste "parfaitement". Quelqu'un voudrait-il sonner? Suis-je en train de manquer quelque chose?
Mike
159

j'utilise

^\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$

Qui est celui utilisé dans ASP.NET par le RegularExpressionValidator.

par Hornshøj-Schierbeck
la source
28
Huer! Mon adresse (mal avisée) de [email protected]est rejetée.
Phrogz
3
Selon cette page data.iana.org/TLD/tlds-alpha-by-domain.txt il n'y a pas de domaines avec juste un seul caractère au niveau supérieur par exemple "quelque chose.c ", "quelque chose.a ", voici la version qui supporte au moins 2 caractères: "quelque chose.pl", "quelque chose.us":^\\w+([-+.']\\w+)*@\\w+([-.]\\w+)*\\.\\w{2,}([-.]\\w+)*$
Tomasz Szulc
4
@Wayne Whitty. Vous avez abordé le problème principal de savoir s'il faut répondre à la grande majorité des adresses, ou TOUTES, y compris celles que personne n'utiliserait, sauf pour tester la validation des e-mails.
Patanjali
@TomaszSzulc barre oblique inverse supplémentaire dans votre réponse est déroutant, je viens de le corriger et la prise en charge des noms de domaine à 2 caractères fonctionne, ^ \ w + ([- +. '] \ W +) * @ \ w + ([-.] \ W +) * \. \ w {2,} ([-.] \ w +) * $
Aqib Mumtaz
2
cela échoue [email protected] qui est en fait valide (un de nos clients avait une adresse similaire) `
Simon_Weaver
142

Je ne sais pas ce qu'il y a de mieux, mais celui-ci est au moins correct, tant que les adresses ont leurs commentaires supprimés et remplacés par des espaces.

Sérieusement. Vous devez utiliser une bibliothèque déjà écrite pour valider les e-mails. La meilleure façon est probablement d'envoyer simplement un e-mail de vérification à cette adresse.

Christian Vest Hansen
la source
2
Pour autant que je sache, certaines bibliothèques ont également tort. Je me souviens vaguement que PHP PEAR avait un tel bug.
bortzmeyer
Cette page a également un avertissement en bas sur quelques éléments de la spécification. que l'expression régulière ne prend pas en charge.
Chris Vest
7
C'est une spécification RFC 822, pas une spécification RFC 5322 .
tchrist
12
En fin de compte, il a raison en ce que la seule façon de valider vraiment une adresse e-mail est de lui envoyer un e-mail et d'attendre une réponse.
Blazemonger
109

Les adresses e-mail que je souhaite valider seront utilisées par une application Web ASP.NET utilisant l'espace de noms System.Net.Mail pour envoyer des e-mails à une liste de personnes. Donc, plutôt que d'utiliser une expression régulière très complexe, j'essaie simplement de créer une instance MailAddress à partir de l'adresse. Le constructeur MailAddress lèvera une exception si l'adresse n'est pas correctement formée. De cette façon, je sais que je peux au moins sortir le courrier électronique de la porte. Bien sûr, il s'agit d'une validation côté serveur, mais au minimum, vous en avez besoin de toute façon.

protected void emailValidator_ServerValidate(object source, ServerValidateEventArgs args)
{
    try
    {
        var a = new MailAddress(txtEmail.Text);
    }
    catch (Exception ex)
    {
        args.IsValid = false;
        emailValidator.ErrorMessage = "email: " + ex.Message;
    }
}
davcar
la source
3
Un bon point. Même si cette validation de serveur rejette une adresse valide, ce n'est pas un problème car vous ne pourrez de toute façon pas envoyer à cette adresse en utilisant cette technologie de serveur particulière. Ou vous pouvez essayer de faire les mêmes choses en utilisant une bibliothèque de messagerie tierce que vous utilisez au lieu des outils par défaut.
Utilisateur
J'aime vraiment la façon dont cela exploite le code du cadre .Net - cela n'a aucun sens de réinventer la roue. C'est excellent. Simple, propre et assure que vous pouvez réellement envoyer l'e-mail. Bon travail.
Cory House
... oui et pour ceux qui s'intéressent à la façon dont il valide, jetez un œil au code dans Reflector - il y en a pas mal - et ce n'est pas une expression régulière!
Tom Carter
2
Juste une note: la classe MailAddress ne correspond pas à RFC5322, si vous voulez juste l'utiliser pour la validation (et non pour l'envoi aussi, auquel cas c'est un point discutable comme mentionné ci-dessus). Voir: stackoverflow.com/questions/6023589/…
porges
Juste un problème mineur: si vous voulez rendre votre code de validation côté serveur plus réutilisable (dans ce cas ou généralement), je suggère d'utiliser args.Valueau lieu de référencer le champ comme txtEmail.Textcodé en dur. Ce dernier liera votre validateur à l'instance de contrôle unique, ce qui peut être OK, tant que vous avez un seul champ e-mail, mais non recommandé autrement.
pholpar
109

Réponse rapide

Utilisez l'expression régulière suivante pour la validation des entrées:

([-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*|"([]!#-[^-~ \t]|(\\[\t -~]))+")@[0-9A-Za-z]([0-9A-Za-z-]{0,61}[0-9A-Za-z])?(\.[0-9A-Za-z]([0-9A-Za-z-]{0,61}[0-9A-Za-z])?)+

Adresses correspondant à cette expression régulière:

  • avoir une partie locale (c'est-à-dire la partie avant le @ -sign) strictement conforme à la RFC 5321/5322,
  • avoir une partie de domaine (c'est-à-dire la partie après le @ -sign) qui est un nom d'hôte avec au moins deux étiquettes, chacune ayant au plus 63 caractères.

La deuxième contrainte est une restriction sur RFC 5321/5322.

Réponse élaborée

L'utilisation d'une expression régulière qui reconnaît les adresses e-mail peut être utile dans diverses situations: par exemple pour rechercher des adresses e-mail dans un document, pour valider la saisie de l'utilisateur ou comme contrainte d'intégrité sur un référentiel de données.

Il convient toutefois de noter que si vous souhaitez savoir si l'adresse fait réellement référence à une boîte aux lettres existante, rien ne peut remplacer l'envoi d'un message à l'adresse. Si vous souhaitez uniquement vérifier si une adresse est grammaticalement correcte, vous pouvez utiliser une expression régulière, mais notez que""@[] s'agit d'une adresse e-mail grammaticalement correcte qui ne fait certainement pas référence à une boîte aux lettres existante.

La syntaxe des adresses e-mail a été définie dans divers RFC , notamment RFC 822 et RFC 5322 . La RFC 822 doit être considérée comme la norme «originale» et la RFC 5322 comme la dernière norme. La syntaxe définie dans la RFC 822 est la plus clémente et les normes ultérieures ont restreint la syntaxe de plus en plus, où les nouveaux systèmes ou services devraient reconnaître la syntaxe obsolète, mais ne jamais la produire.

Dans cette réponse, je considérerai «adresse e-mail» addr-speccomme défini dans les RFC (c'est [email protected]-à- dire , mais pas "John Doe"<[email protected]>, ni some-group:[email protected],[email protected];).

Il y a un problème avec la traduction des syntaxes RFC en expressions régulières: les syntaxes ne sont pas régulières! En effet, ils permettent des commentaires facultatifs dans les adresses e-mail qui peuvent être imbriquées à l'infini, tandis que l'imbrication à l'infini ne peut pas être décrite par une expression régulière. Pour rechercher ou valider des adresses contenant des commentaires, vous avez besoin d'un analyseur ou d'expressions plus puissantes. (Notez que les langages comme Perl ont des constructions pour décrire les grammaires sans contexte d'une manière regex.) Dans cette réponse, je vais ignorer les commentaires et ne considérer que les expressions régulières appropriées.

Les RFC définissent les syntaxes des e-mails et non des adresses e-mail en tant que telles. Les adresses peuvent apparaître dans divers champs d'en-tête et c'est là qu'elles sont principalement définies. Lorsqu'elles apparaissent dans les champs d'en-tête, les adresses peuvent contenir (entre des jetons lexicaux) des espaces, des commentaires et même des sauts de ligne. Sémantiquement, cela n'a cependant aucune signification. En supprimant cet espace, etc. d'une adresse, vous obtenez une représentation canonique sémantiquement équivalente . Ainsi, la représentation canonique de first. last (comment) @ [3.5.7.9]est first.last@[3.5.7.9].

Différentes syntaxes doivent être utilisées à des fins différentes. Si vous souhaitez rechercher des adresses e-mail dans un document (peut-être très ancien), il peut être judicieux d'utiliser la syntaxe définie dans la RFC 822. En revanche, si vous souhaitez valider la saisie utilisateur, vous pouvez utiliser le syntaxe telle que définie dans la RFC 5322, n'acceptant probablement que des représentations canoniques. Vous devez décider quelle syntaxe s'applique à votre cas spécifique.

J'utilise des expressions régulières "étendues" POSIX dans cette réponse, en supposant un jeu de caractères compatible ASCII.

RFC 822

Je suis arrivé à l'expression régulière suivante. J'invite tout le monde à essayer de le casser. Si vous trouvez des faux positifs ou des faux négatifs, veuillez les poster dans un commentaire et j'essaierai de corriger l'expression dès que possible.

([^][()<>@,;:\\". \x00-\x1F\x7F]+|"(\n|(\\\r)*([^"\\\r\n]|\\[^\r]))*(\\\r)*")(\.([^][()<>@,;:\\". \x00-\x1F\x7F]+|"(\n|(\\\r)*([^"\\\r\n]|\\[^\r]))*(\\\r)*"))*@([^][()<>@,;:\\". \x00-\x1F\x7F]+|\[(\n|(\\\r)*([^][\\\r\n]|\\[^\r]))*(\\\r)*])(\.([^][()<>@,;:\\". \x00-\x1F\x7F]+|\[(\n|(\\\r)*([^][\\\r\n]|\\[^\r]))*(\\\r)*]))*

Je crois qu'il est entièrement conforme à la RFC 822, y compris les errata . Il reconnaît uniquement les adresses e-mail sous leur forme canonique. Pour une expression régulière qui reconnaît (pliant) les espaces blancs, voir la dérivation ci-dessous.

La dérivation montre comment je suis arrivé à l'expression. Je liste toutes les règles de grammaire pertinentes de la RFC exactement telles qu'elles apparaissent, suivies de l'expression rationnelle correspondante. Lorsqu'un erratum a été publié, je donne une expression distincte pour la règle de grammaire corrigée (marquée "erratum") et j'utilise la version mise à jour comme sous-expression dans les expressions régulières suivantes.

Comme indiqué au paragraphe 3.1.4. du RFC 822, un espace blanc linéaire optionnel peut être inséré entre les jetons lexicaux. Le cas échéant, j'ai développé les expressions pour tenir compte de cette règle et marqué le résultat avec "opt-lwsp".

CHAR        =  <any ASCII character>
            =~ .

CTL         =  <any ASCII control character and DEL>
            =~ [\x00-\x1F\x7F]

CR          =  <ASCII CR, carriage return>
            =~ \r

LF          =  <ASCII LF, linefeed>
            =~ \n

SPACE       =  <ASCII SP, space>
            =~  

HTAB        =  <ASCII HT, horizontal-tab>
            =~ \t

<">         =  <ASCII quote mark>
            =~ "

CRLF        =  CR LF
            =~ \r\n

LWSP-char   =  SPACE / HTAB
            =~ [ \t]

linear-white-space =  1*([CRLF] LWSP-char)
                   =~ ((\r\n)?[ \t])+

specials    =  "(" / ")" / "<" / ">" / "@" /  "," / ";" / ":" / "\" / <"> /  "." / "[" / "]"
            =~ [][()<>@,;:\\".]

quoted-pair =  "\" CHAR
            =~ \\.

qtext       =  <any CHAR excepting <">, "\" & CR, and including linear-white-space>
            =~ [^"\\\r]|((\r\n)?[ \t])+

dtext       =  <any CHAR excluding "[", "]", "\" & CR, & including linear-white-space>
            =~ [^][\\\r]|((\r\n)?[ \t])+

quoted-string  =  <"> *(qtext|quoted-pair) <">
               =~ "([^"\\\r]|((\r\n)?[ \t])|\\.)*"
(erratum)      =~ "(\n|(\\\r)*([^"\\\r\n]|\\[^\r]|(\r\n)?[ \t]))*(\\\r)*"

domain-literal =  "[" *(dtext|quoted-pair) "]"
               =~ \[([^][\\\r]|((\r\n)?[ \t])|\\.)*]
(erratum)      =~ \[(\n|(\\\r)*([^][\\\r\n]|\\[^\r]|(\r\n)?[ \t]))*(\\\r)*]

atom        =  1*<any CHAR except specials, SPACE and CTLs>
            =~ [^][()<>@,;:\\". \x00-\x1F\x7F]+

word        =  atom / quoted-string
            =~ [^][()<>@,;:\\". \x00-\x1F\x7F]+|"(\n|(\\\r)*([^"\\\r\n]|\\[^\r]|(\r\n)?[ \t]))*(\\\r)*"

domain-ref  =  atom

sub-domain  =  domain-ref / domain-literal
            =~ [^][()<>@,;:\\". \x00-\x1F\x7F]+|\[(\n|(\\\r)*([^][\\\r\n]|\\[^\r]|(\r\n)?[ \t]))*(\\\r)*]

local-part  =  word *("." word)
            =~ ([^][()<>@,;:\\". \x00-\x1F\x7F]+|"(\n|(\\\r)*([^"\\\r\n]|\\[^\r]|(\r\n)?[ \t]))*(\\\r)*")(\.([^][()<>@,;:\\". \x00-\x1F\x7F]+|"(\n|(\\\r)*([^"\\\r\n]|\\[^\r]|(\r\n)?[ \t]))*(\\\r)*"))*
(opt-lwsp)  =~ ([^][()<>@,;:\\". \x00-\x1F\x7F]+|"(\n|(\\\r)*([^"\\\r\n]|\\[^\r]|(\r\n)?[ \t]))*(\\\r)*")(((\r\n)?[ \t])*\.((\r\n)?[ \t])*([^][()<>@,;:\\". \x00-\x1F\x7F]+|"(\n|(\\\r)*([^"\\\r\n]|\\[^\r]|(\r\n)?[ \t]))*(\\\r)*"))*

domain      =  sub-domain *("." sub-domain)
            =~ ([^][()<>@,;:\\". \x00-\x1F\x7F]+|\[(\n|(\\\r)*([^][\\\r\n]|\\[^\r]|(\r\n)?[ \t]))*(\\\r)*])(\.([^][()<>@,;:\\". \x00-\x1F\x7F]+|\[(\n|(\\\r)*([^][\\\r\n]|\\[^\r]|(\r\n)?[ \t]))*(\\\r)*]))*
(opt-lwsp)  =~ ([^][()<>@,;:\\". \x00-\x1F\x7F]+|\[(\n|(\\\r)*([^][\\\r\n]|\\[^\r]|(\r\n)?[ \t]))*(\\\r)*])(((\r\n)?[ \t])*\.((\r\n)?[ \t])*([^][()<>@,;:\\". \x00-\x1F\x7F]+|\[(\n|(\\\r)*([^][\\\r\n]|\\[^\r]|(\r\n)?[ \t]))*(\\\r)*]))*

addr-spec   =  local-part "@" domain
            =~ ([^][()<>@,;:\\". \x00-\x1F\x7F]+|"(\n|(\\\r)*([^"\\\r\n]|\\[^\r]|(\r\n)?[ \t]))*(\\\r)*")(\.([^][()<>@,;:\\". \x00-\x1F\x7F]+|"(\n|(\\\r)*([^"\\\r\n]|\\[^\r]|(\r\n)?[ \t]))*(\\\r)*"))*@([^][()<>@,;:\\". \x00-\x1F\x7F]+|\[(\n|(\\\r)*([^][\\\r\n]|\\[^\r]|(\r\n)?[ \t]))*(\\\r)*])(\.([^][()<>@,;:\\". \x00-\x1F\x7F]+|\[(\n|(\\\r)*([^][\\\r\n]|\\[^\r]|(\r\n)?[ \t]))*(\\\r)*]))*
(opt-lwsp)  =~ ([^][()<>@,;:\\". \x00-\x1F\x7F]+|"(\n|(\\\r)*([^"\\\r\n]|\\[^\r]|(\r\n)?[ \t]))*(\\\r)*")((\r\n)?[ \t])*(\.((\r\n)?[ \t])*([^][()<>@,;:\\". \x00-\x1F\x7F]+|"(\n|(\\\r)*([^"\\\r\n]|\\[^\r]|(\r\n)?[ \t]))*(\\\r)*")((\r\n)?[ \t])*)*@((\r\n)?[ \t])*([^][()<>@,;:\\". \x00-\x1F\x7F]+|\[(\n|(\\\r)*([^][\\\r\n]|\\[^\r]|(\r\n)?[ \t]))*(\\\r)*])(((\r\n)?[ \t])*\.((\r\n)?[ \t])*([^][()<>@,;:\\". \x00-\x1F\x7F]+|\[(\n|(\\\r)*([^][\\\r\n]|\\[^\r]|(\r\n)?[ \t]))*(\\\r)*]))*
(canonical) =~ ([^][()<>@,;:\\". \x00-\x1F\x7F]+|"(\n|(\\\r)*([^"\\\r\n]|\\[^\r]))*(\\\r)*")(\.([^][()<>@,;:\\". \x00-\x1F\x7F]+|"(\n|(\\\r)*([^"\\\r\n]|\\[^\r]))*(\\\r)*"))*@([^][()<>@,;:\\". \x00-\x1F\x7F]+|\[(\n|(\\\r)*([^][\\\r\n]|\\[^\r]))*(\\\r)*])(\.([^][()<>@,;:\\". \x00-\x1F\x7F]+|\[(\n|(\\\r)*([^][\\\r\n]|\\[^\r]))*(\\\r)*]))*

RFC 5322

Je suis arrivé à l'expression régulière suivante. J'invite tout le monde à essayer de le casser. Si vous trouvez des faux positifs ou des faux négatifs, veuillez les poster dans un commentaire et j'essaierai de corriger l'expression dès que possible.

([-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*|"([]!#-[^-~ \t]|(\\[\t -~]))+")@([-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*|\[[\t -Z^-~]*])

Je crois qu'il est entièrement conforme à la RFC 5322, y compris les errata . Il reconnaît uniquement les adresses e-mail sous leur forme canonique. Pour une expression régulière qui reconnaît (pliant) les espaces blancs, voir la dérivation ci-dessous.

La dérivation montre comment je suis arrivé à l'expression. Je liste toutes les règles de grammaire pertinentes de la RFC exactement telles qu'elles apparaissent, suivies de l'expression rationnelle correspondante. Pour les règles qui incluent des espaces blancs sémantiquement non pertinents (pliants), je donne une expression régulière distincte marquée "(normalisée)" qui n'accepte pas ces espaces blancs.

J'ai ignoré toutes les règles "obs-" de la RFC. Cela signifie que les expressions rationnelles correspondent uniquement aux adresses e-mail strictement conformes à la RFC 5322. Si vous devez faire correspondre les «anciennes» adresses (comme le fait la grammaire plus souple, y compris les règles «obs»), vous pouvez utiliser l'une des expressions rationnelles RFC 822 du paragraphe précédent.

VCHAR           =   %x21-7E
                =~  [!-~]

ALPHA           =   %x41-5A / %x61-7A
                =~  [A-Za-z]

DIGIT           =   %x30-39
                =~  [0-9]

HTAB            =   %x09
                =~  \t

CR              =   %x0D
                =~  \r

LF              =   %x0A
                =~  \n

SP              =   %x20
                =~  

DQUOTE          =   %x22
                =~  "

CRLF            =   CR LF
                =~  \r\n

WSP             =   SP / HTAB
                =~  [\t ]

quoted-pair     =   "\" (VCHAR / WSP)
                =~  \\[\t -~]

FWS             =   ([*WSP CRLF] 1*WSP)
                =~  ([\t ]*\r\n)?[\t ]+

ctext           =   %d33-39 / %d42-91 / %d93-126
                =~  []!-'*-[^-~]

("comment" is left out in the regex)
ccontent        =   ctext / quoted-pair / comment
                =~  []!-'*-[^-~]|(\\[\t -~])

(not regular)
comment         =   "(" *([FWS] ccontent) [FWS] ")"

(is equivalent to FWS when leaving out comments)
CFWS            =   (1*([FWS] comment) [FWS]) / FWS
                =~  ([\t ]*\r\n)?[\t ]+

atext           =   ALPHA / DIGIT / "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "/" / "=" / "?" / "^" / "_" / "`" / "{" / "|" / "}" / "~"
                =~  [-!#-'*+/-9=?A-Z^-~]

dot-atom-text   =   1*atext *("." 1*atext)
                =~  [-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*

dot-atom        =   [CFWS] dot-atom-text [CFWS]
                =~  (([\t ]*\r\n)?[\t ]+)?[-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*(([\t ]*\r\n)?[\t ]+)?
(normalized)    =~  [-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*

qtext           =   %d33 / %d35-91 / %d93-126
                =~  []!#-[^-~]

qcontent        =   qtext / quoted-pair
                =~  []!#-[^-~]|(\\[\t -~])

(erratum)
quoted-string   =   [CFWS] DQUOTE ((1*([FWS] qcontent) [FWS]) / FWS) DQUOTE [CFWS]
                =~  (([\t ]*\r\n)?[\t ]+)?"(((([\t ]*\r\n)?[\t ]+)?([]!#-[^-~]|(\\[\t -~])))+(([\t ]*\r\n)?[\t ]+)?|(([\t ]*\r\n)?[\t ]+)?)"(([\t ]*\r\n)?[\t ]+)?
(normalized)    =~  "([]!#-[^-~ \t]|(\\[\t -~]))+"

dtext           =   %d33-90 / %d94-126
                =~  [!-Z^-~]

domain-literal  =   [CFWS] "[" *([FWS] dtext) [FWS] "]" [CFWS]
                =~  (([\t ]*\r\n)?[\t ]+)?\[((([\t ]*\r\n)?[\t ]+)?[!-Z^-~])*(([\t ]*\r\n)?[\t ]+)?](([\t ]*\r\n)?[\t ]+)?
(normalized)    =~  \[[\t -Z^-~]*]

local-part      =   dot-atom / quoted-string
                =~  (([\t ]*\r\n)?[\t ]+)?[-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*(([\t ]*\r\n)?[\t ]+)?|(([\t ]*\r\n)?[\t ]+)?"(((([\t ]*\r\n)?[\t ]+)?([]!#-[^-~]|(\\[\t -~])))+(([\t ]*\r\n)?[\t ]+)?|(([\t ]*\r\n)?[\t ]+)?)"(([\t ]*\r\n)?[\t ]+)?
(normalized)    =~  [-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*|"([]!#-[^-~ \t]|(\\[\t -~]))+"

domain          =   dot-atom / domain-literal
                =~  (([\t ]*\r\n)?[\t ]+)?[-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*(([\t ]*\r\n)?[\t ]+)?|(([\t ]*\r\n)?[\t ]+)?\[((([\t ]*\r\n)?[\t ]+)?[!-Z^-~])*(([\t ]*\r\n)?[\t ]+)?](([\t ]*\r\n)?[\t ]+)?
(normalized)    =~  [-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*|\[[\t -Z^-~]*]

addr-spec       =   local-part "@" domain
                =~  ((([\t ]*\r\n)?[\t ]+)?[-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*(([\t ]*\r\n)?[\t ]+)?|(([\t ]*\r\n)?[\t ]+)?"(((([\t ]*\r\n)?[\t ]+)?([]!#-[^-~]|(\\[\t -~])))+(([\t ]*\r\n)?[\t ]+)?|(([\t ]*\r\n)?[\t ]+)?)"(([\t ]*\r\n)?[\t ]+)?)@((([\t ]*\r\n)?[\t ]+)?[-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*(([\t ]*\r\n)?[\t ]+)?|(([\t ]*\r\n)?[\t ]+)?\[((([\t ]*\r\n)?[\t ]+)?[!-Z^-~])*(([\t ]*\r\n)?[\t ]+)?](([\t ]*\r\n)?[\t ]+)?)
(normalized)    =~  ([-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*|"([]!#-[^-~ \t]|(\\[\t -~]))+")@([-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*|\[[\t -Z^-~]*])

Notez que certaines sources (notamment w3c ) affirment que la RFC 5322 est trop stricte sur la partie locale (c'est-à-dire la partie avant le @ -sign). En effet, "..", "a..b" et "a". ne sont pas des atomes de point valides, alors qu'ils peuvent être utilisés comme noms de boîtes aux lettres. Le RFC, cependant, ne permet de pièces locales comme celles - ci, sauf qu'ils doivent être cités. Donc au lieu de [email protected]vous devriez écrire "a..b"@example.net, ce qui est sémantiquement équivalent.

D'autres restrictions

SMTP (tel que défini dans la RFC 5321 ) restreint davantage l'ensemble des adresses e-mail valides (ou en fait: les noms de boîtes aux lettres). Il semble raisonnable d'imposer cette grammaire plus stricte, afin que l'adresse e-mail correspondante puisse être utilisée pour envoyer un e-mail.

La RFC 5321 laisse essentiellement la partie "locale" (c'est-à-dire la partie avant le @ -sign), mais est plus stricte sur la partie du domaine (c'est-à-dire la partie après le @ -sign). Il autorise uniquement les noms d'hôte à la place des atomes de point et les littéraux d'adresse à la place des littéraux de domaine.

La grammaire présentée dans RFC 5321 est trop indulgente en ce qui concerne à la fois les noms d'hôte et les adresses IP. J'ai pris la liberté de "corriger" les règles en question, en utilisant ce projet et la RFC 1034 comme lignes directrices. Voici l'expression régulière résultante.

([-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*|"([]!#-[^-~ \t]|(\\[\t -~]))+")@([0-9A-Za-z]([0-9A-Za-z-]{0,61}[0-9A-Za-z])?(\.[0-9A-Za-z]([0-9A-Za-z-]{0,61}[0-9A-Za-z])?)*|\[((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|IPv6:((((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){6}|::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){5}|[0-9A-Fa-f]{0,4}::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){4}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):)?(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){3}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,2}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){2}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,3}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,4}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::)((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3})|(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3})|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,5}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3})|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,6}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::)|(?!IPv6:)[0-9A-Za-z-]*[0-9A-Za-z]:[!-Z^-~]+)])

Notez que selon le cas d'utilisation, vous ne voudrez peut-être pas autoriser un "littéral d'adresse générale" dans votre expression régulière. Notez également que j'ai utilisé un lookahead négatif (?!IPv6:)dans l' expression régulière pour empêcher la partie "General-address-literal" de faire correspondre les adresses IPv6 malformées. Certains processeurs regex ne prennent pas en charge l'anticipation négative. Retirez la sous-chaîne|(?!IPv6:)[0-9A-Za-z-]*[0-9A-Za-z]:[!-Z^-~]+ de l'expression régulière si vous souhaitez supprimer toute la partie "General-address-literal".

Voici la dérivation:

Let-dig         =   ALPHA / DIGIT
                =~  [0-9A-Za-z]

Ldh-str         =   *( ALPHA / DIGIT / "-" ) Let-dig
                =~  [0-9A-Za-z-]*[0-9A-Za-z]

(regex is updated to make sure sub-domains are max. 63 charactes long - RFC 1034 section 3.5)
sub-domain      =   Let-dig [Ldh-str]
                =~  [0-9A-Za-z]([0-9A-Za-z-]{0,61}[0-9A-Za-z])?

Domain          =   sub-domain *("." sub-domain)
                =~  [0-9A-Za-z]([0-9A-Za-z-]{0,61}[0-9A-Za-z])?(\.[0-9A-Za-z]([0-9A-Za-z-]{0,61}[0-9A-Za-z])?)*

Snum            =   1*3DIGIT
                =~  [0-9]{1,3}

(suggested replacement for "Snum")
ip4-octet       =   DIGIT / %x31-39 DIGIT / "1" 2DIGIT / "2" %x30-34 DIGIT / "25" %x30-35
                =~  25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9]

IPv4-address-literal    =   Snum 3("."  Snum)
                        =~  [0-9]{1,3}(\.[0-9]{1,3}){3}

(suggested replacement for "IPv4-address-literal")
ip4-address     =   ip4-octet 3("." ip4-octet)
                =~  (25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}

(suggested replacement for "IPv6-hex")
ip6-h16         =   "0" / ( (%x49-57 / %x65-70 /%x97-102) 0*3(%x48-57 / %x65-70 /%x97-102) )
                =~  0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}

(not from RFC)
ls32            =   ip6-h16 ":" ip6-h16 / ip4-address
                =~  (0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3})|(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}

(suggested replacement of "IPv6-addr")
ip6-address     =                                      6(ip6-h16 ":") ls32
                    /                             "::" 5(ip6-h16 ":") ls32
                    / [                 ip6-h16 ] "::" 4(ip6-h16 ":") ls32
                    / [ *1(ip6-h16 ":") ip6-h16 ] "::" 3(ip6-h16 ":") ls32
                    / [ *2(ip6-h16 ":") ip6-h16 ] "::" 2(ip6-h16 ":") ls32
                    / [ *3(ip6-h16 ":") ip6-h16 ] "::"   ip6-h16 ":"  ls32
                    / [ *4(ip6-h16 ":") ip6-h16 ] "::"                ls32
                    / [ *5(ip6-h16 ":") ip6-h16 ] "::"   ip6-h16
                    / [ *6(ip6-h16 ":") ip6-h16 ] "::"
                =~  (((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){6}|::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){5}|[0-9A-Fa-f]{0,4}::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){4}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):)?(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){3}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,2}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){2}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,3}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,4}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::)((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3})|(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3})|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,5}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3})|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,6}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::

IPv6-address-literal    =   "IPv6:" ip6-address
                        =~  IPv6:((((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){6}|::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){5}|[0-9A-Fa-f]{0,4}::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){4}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):)?(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){3}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,2}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){2}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,3}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,4}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::)((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3})|(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3})|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,5}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3})|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,6}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::)

Standardized-tag        =   Ldh-str
                        =~  [0-9A-Za-z-]*[0-9A-Za-z]

dcontent        =   %d33-90 / %d94-126
                =~  [!-Z^-~]

General-address-literal =   Standardized-tag ":" 1*dcontent
                        =~  [0-9A-Za-z-]*[0-9A-Za-z]:[!-Z^-~]+

address-literal =   "[" ( IPv4-address-literal / IPv6-address-literal / General-address-literal ) "]"
                =~  \[((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|IPv6:((((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){6}|::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){5}|[0-9A-Fa-f]{0,4}::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){4}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):)?(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){3}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,2}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){2}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,3}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,4}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::)((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3})|(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3})|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,5}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3})|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,6}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::)|(?!IPv6:)[0-9A-Za-z-]*[0-9A-Za-z]:[!-Z^-~]+)]

Mailbox         =   Local-part "@" ( Domain / address-literal )
                =~  ([-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*|"([]!#-[^-~ \t]|(\\[\t -~]))+")@([0-9A-Za-z]([0-9A-Za-z-]{0,61}[0-9A-Za-z])?(\.[0-9A-Za-z]([0-9A-Za-z-]{0,61}[0-9A-Za-z])?)*|\[((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|IPv6:((((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){6}|::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){5}|[0-9A-Fa-f]{0,4}::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){4}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):)?(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){3}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,2}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){2}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,3}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,4}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::)((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3})|(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3})|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,5}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3})|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,6}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::)|(?!IPv6:)[0-9A-Za-z-]*[0-9A-Za-z]:[!-Z^-~]+)])

Validation des entrées utilisateur

Un cas d'utilisation courant est la validation des entrées utilisateur, par exemple sur un formulaire html. Dans ce cas, il est généralement raisonnable d'exclure les littéraux d'adresse et d'exiger au moins deux étiquettes dans le nom d'hôte. En prenant comme base l'expression rationnelle RFC 5321 améliorée de la section précédente, l'expression résultante serait:

([-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*|"([]!#-[^-~ \t]|(\\[\t -~]))+")@[0-9A-Za-z]([0-9A-Za-z-]{0,61}[0-9A-Za-z])?(\.[0-9A-Za-z]([0-9A-Za-z-]{0,61}[0-9A-Za-z])?)+

Je ne recommande pas de restreindre davantage la partie locale, par exemple en excluant les chaînes entre guillemets, car nous ne savons pas quel type de noms de boîte aux lettres certains hôtes autorisent (comme "a..b"@example.netou même "a b"@example.net).

Je ne recommande pas non plus de valider explicitement par rapport à une liste de domaines de premier niveau littéraux ou même d'imposer des contraintes de longueur (rappelez-vous comment ".museum" est invalidé [a-z]{2,4}), mais si vous devez:

([-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*|"([]!#-[^-~ \t]|(\\[\t -~]))+")@([0-9A-Za-z]([0-9A-Za-z-]{0,61}[0-9A-Za-z])?\.)*(net|org|com|info|etc...)

Assurez-vous de garder votre regex à jour si vous décidez de suivre le chemin de la validation explicite de domaine de premier niveau.

Considérations supplémentaires

Lorsqu'ils acceptent uniquement les noms d'hôte dans la partie domaine (après le signe @), les expressions rationnelles ci-dessus n'acceptent que les étiquettes avec au plus 63 caractères, comme elles le devraient. Cependant, ils n'imposent pas le fait que le nom d'hôte entier doit contenir au plus 253 caractères (y compris les points). Bien que cette contrainte soit à proprement parler encore régulière, il n'est pas possible de faire une regex qui incorpore cette règle.

Une autre considération, en particulier lors de l'utilisation des expressions rationnelles pour la validation des entrées, est le retour d'information à l'utilisateur. Si un utilisateur entre une adresse incorrecte, ce serait bien de donner un peu plus de commentaires qu'une simple "adresse syntaxiquement incorrecte". Avec les expressions régulières "vanille", ce n'est pas possible.

Ces deux considérations pourraient être traitées en analysant l'adresse. Dans certains cas, la contrainte de longueur supplémentaire sur les noms d'hôte peut également être traitée en utilisant une expression régulière supplémentaire qui la vérifie et en faisant correspondre l'adresse avec les deux expressions.

Aucun des regex de cette réponse n'est optimisé pour les performances. Si les performances posent problème, vous devriez voir si (et comment) l'expression rationnelle de votre choix peut être optimisée.

Rinke
la source
3
RFC 6532 met à jour 5322 pour autoriser et inclure un UTF-8 complet et propre. Détails supplémentaires ici .
Selon wikipedia, la partie locale, lorsqu'elle est pointillée, a une limitation de 64 caractères par partie, et la RFC 5322 fait également référence à la partie locale pointillée à interpréter avec les restrictions des domaines. Par exemple arbitrary-long-email-address-should-be-invalid-arbitrary-long-email-address-should-be-invalid.and-the-second-group-also-should-not-be-so-long-and-the-second-group-also-should-not-be-so-long@example.com, ne devrait pas valider. Je suggère de changer les signes "+" dans le premier groupe (nom avant le point facultatif) et dans le deuxième groupe (nom après les points suivants) en{1,64}
Xavi Montero
Comme les commentaires sont de taille limitée, voici la regex résultante que je prévois d'utiliser, qui est celle au début de cette réponse, plus la limitation de la taille dans la partie locale, plus l'ajout d'une barre oblique inverse avant le "/" symbole tel que requis par PHP et aussi dans regex101.com: En PHP j'utilise:$emailRegex = '/^([-!#-\'*+\/-9=?A-Z^-~]{1,64}(\.[-!#-\'*+\/-9=?A-Z^-~]{1,64})*|"([]!#-[^-~ \t]|(\\[\t -~]))+")@[0-9A-Za-z]([0-9A-Za-z-]{0,61}[0-9A-Za-z])?(\.[0-9A-Za-z]([0-9A-Za-z-]{0,61}[0-9A-Za-z])?)+$/';
Xavi Montero
ATTENTION: pour une raison quelconque, StackOverflow ajoute des caractères masqués lors de la copie à partir de la démarque rendue. Copiez-le dans le regex101.com et vous verrez des points noirs là-bas. Vous devez les supprimer et corriger la chaîne ... Peut-être que si intégrés dans la réponse, ils sont correctement copiables. Désolé pour le dérangement. Je ne veux pas ajouter de nouvelle réponse car celle-ci est la bonne. De plus, je ne veux pas éditer directement, sauf si la communauté pense que cela devrait être intégré.
Xavi Montero
@XaviMontero Merci d'avoir contribué à Xavi! Avez-vous une référence à la RFC indiquant la limite de 64 caractères sur les étiquettes de pièces locales? Si c'est le cas, je serais ravi d'ajuster la réponse.
Rinke
73

Il existe de nombreux exemples de cela sur le net (et je pense que même un qui valide pleinement le RFC - mais il fait des dizaines / centaines de lignes si la mémoire est bonne). Les gens ont tendance à s'emballer en validant ce genre de choses. Pourquoi ne pas simplement vérifier qu'il a un @ et au moins un. et répond à une longueur minimale simple. Il est trivial de saisir un faux e-mail et de toujours correspondre à toute expression rationnelle valide. Je suppose que les faux positifs valent mieux que les faux négatifs.

Draemon
la source
1
Oui, mais quel RFC? :) Ce [validateur RFC ‐ 5322] ( stackoverflow.com/questions/201323/… ) ne fait qu'une quarantaine de lignes.
tchrist
14
UNE . n'est pas requis. Un TLD peut avoir des adresses e-mail, ou il peut y avoir une adresse IPv6
Sijmen Mulder
1
Les RFC ne sont pas la fin de l'histoire: l'ICANN n'autorise plus les domaines «sans points»: icann.org/news/announcement-2013-08-30-en
Synchro
64

Lorsque vous décidez quels caractères sont autorisés, n'oubliez pas vos amis apostrophés et avec un trait d'union. Je n'ai aucun contrôle sur le fait que mon entreprise génère mon adresse e-mail en utilisant mon nom à partir du système RH. Cela inclut l'apostrophe dans mon nom de famille. Je ne peux pas vous dire combien de fois j'ai été empêché d'interagir avec un site Web du fait que mon adresse e-mail est "invalide".

DOK
la source
4
Il s'agit d'un problème très courant dans les programmes qui font des hypothèses injustifiées sur ce qui est et n'est pas autorisé au nom d'une personne. Il ne faut pas faire de telles hypothèses, il suffit d'accepter n'importe quel caractère que les RFC pertinentes disent qu'il faut.
tchrist
4
Oui. Je suis particulièrement en colère contre les programmeurs qui rejettent les majuscules dans les adresses e-mail! Idiot et / ou paresseux.
PhiLho
63

Cette expression régulière provient de la bibliothèque Email :: Valid de Perl . Je pense que c'est le plus précis, il correspond à tous les 822. Et, il est basé sur l'expression régulière dans le livre O'Reilly:

Expression régulière construite à l'aide de l'exemple de Jeffrey Friedl dans Mastering Regular Expressions ( http://www.ora.com/catalog/regexp/ ).

$RFC822PAT = <<'EOF';
[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\
xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xf
f\n\015()]*)*\)[\040\t]*)*(?:(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\x
ff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|"[^\\\x80-\xff\n\015
"]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015"]*)*")[\040\t]*(?:\([^\\\x80-\
xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80
-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*
)*(?:\.[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\
\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\
x80-\xff\n\015()]*)*\)[\040\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x8
0-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|"[^\\\x80-\xff\n
\015"]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015"]*)*")[\040\t]*(?:\([^\\\x
80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^
\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040
\t]*)*)*@[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([
^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\
\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\
x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-
\xff\n\015\[\]]|\\[^\x80-\xff])*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()
]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\
x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:\.[\04
0\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\
n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\
015()]*)*\)[\040\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?!
[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\
]]|\\[^\x80-\xff])*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\
x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\01
5()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*)*|(?:[^(\040)<>@,;:".
\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]
)|"[^\\\x80-\xff\n\015"]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015"]*)*")[^
()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037]*(?:(?:\([^\\\x80-\xff\n\0
15()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][
^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)|"[^\\\x80-\xff\
n\015"]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015"]*)*")[^()<>@,;:".\\\[\]\
x80-\xff\000-\010\012-\037]*)*<[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?
:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-
\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:@[\040\t]*
(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015
()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()
]*)*\)[\040\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\0
40)<>@,;:".\\\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|\\
[^\x80-\xff])*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\
xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*
)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:\.[\040\t]*(?:\([^\\\x80
-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x
80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t
]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\
\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|\\[^\x80-\xff])
*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x
80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80
-\xff\n\015()]*)*\)[\040\t]*)*)*(?:,[\040\t]*(?:\([^\\\x80-\xff\n\015(
)]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\
\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*@[\040\t
]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\0
15()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015
()]*)*\)[\040\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(
\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|
\\[^\x80-\xff])*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80
-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()
]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:\.[\040\t]*(?:\([^\\\x
80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^
\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040
\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".
\\\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|\\[^\x80-\xff
])*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\
\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x
80-\xff\n\015()]*)*\)[\040\t]*)*)*)*:[\040\t]*(?:\([^\\\x80-\xff\n\015
()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\
\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*)?(?:[^
(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-
\037\x80-\xff])|"[^\\\x80-\xff\n\015"]*(?:\\[^\x80-\xff][^\\\x80-\xff\
n\015"]*)*")[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|
\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))
[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:\.[\040\t]*(?:\([^\\\x80-\xff
\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\x
ff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(
?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\
000-\037\x80-\xff])|"[^\\\x80-\xff\n\015"]*(?:\\[^\x80-\xff][^\\\x80-\
xff\n\015"]*)*")[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\x
ff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)
*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*)*@[\040\t]*(?:\([^\\\x80-\x
ff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-
\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)
*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\
]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|\\[^\x80-\xff])*\]
)[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-
\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\x
ff\n\015()]*)*\)[\040\t]*)*(?:\.[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(
?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80
-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:[^(\040)<
>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x8
0-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|\\[^\x80-\xff])*\])[\040\t]*(?:
\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]
*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)
*\)[\040\t]*)*)*>)
EOF
Evan Carroll
la source
14
O_O, vous devez également être un maître des regex pour comprendre ce qu'il fait
Chris McGrath
45

Lorsque vous écrivez en PHP, je vous conseille d'utiliser la validation intégrée PHP pour les e-mails.

filter_var($value, FILTER_VALIDATE_EMAIL)

Si vous utilisez une version php inférieure à 5.3.6, veuillez être conscient de ce problème: https://bugs.php.net/bug.php?id=53091

Si vous souhaitez plus d'informations sur le fonctionnement de cette validation intégrée, voir ici: Le filtre filter_var FILTER_VALIDATE_EMAIL de PHP fonctionne-t-il réellement?

SimonSimCity
la source
obtient un vote, exactement ce que j'allais dire. Ne gère pas les IDN mais la conversion en code chétif au préalable résout ce problème. PHP> = 5.3 a idn_to_ascii () pour cela. L'un des moyens les plus simples et les plus efficaces pour valider un e-mail.
Taylor
43

Cal Henderson (Flickr) a écrit un article intitulé Parsing Email Adresses en PHP et montre comment effectuer une analyse correcte des adresses e-mail conformes à la RFC (2) 822. Vous pouvez également obtenir le code source en php , python et ruby sous licence cc .

adnam
la source
il m'a dit que a@bc'était valide
dsdsdsdsd
1
@dsdsdsdsd Parce que a@best valide ... dans ce cas best le domaine de premier niveau.
rink.attendant.6
42

Je n'ai jamais pris la peine de créer avec ma propre expression régulière, car il est probable que quelqu'un d'autre ait déjà trouvé une meilleure version. J'utilise toujours regexlib pour en trouver un à mon goût.

Kon
la source
1
Cela a été signalé pour la longueur et le contenu, mais c'est toujours une bonne contribution avec 41 votes et ne devrait pas être supprimé.
Will
37

Il n'y en a pas de vraiment utilisable.
Je discute de certains problèmes dans ma réponse à Existe-t-il une bibliothèque php pour la validation de l'adresse e-mail? , il est également abordé dans Regexp reconnaissance d'adresse e-mail difficile?

En bref, ne vous attendez pas à ce qu'une seule expression rationnelle utilisable fasse un bon travail. Et le meilleur regex validera la syntaxe, pas la validité d'un e-mail ([email protected] est correct mais il rebondira probablement ...).

PhiLho
la source
Corrigez-moi si je me trompe, mais je crois que PHP utilise des modèles PCRE. Si c'est le cas, vous devriez pouvoir créer quelque chose de similaire au modèle RFC 5322 d'Abigail .
tchrist
@tchrist: je ne sais pas si PCRE a rattrapé cette syntaxe (que je découvre). Si c'est le cas, je ne sais pas si le PCRE de PHP a rattrapé cette version de PCRE ... Eh bien, si je comprends bien cette syntaxe, vous pouvez également utiliser un analyseur PEG, beaucoup plus clair et complet qu'un regex de toute façon.
PhiLho
PCRE l' a rattrapé, mais peut-être que PHP n'a pas rattrapé PCRE. ☹
tchrist
36

Une expression régulière simple qui ne rejetterait au moins aucune adresse e-mail valide serait de vérifier quelque chose, suivi d'un signe @ puis de quelque chose suivi d'un point et d'au moins 2 choses. Il ne rejettera rien, mais après avoir examiné les spécifications, je ne trouve aucun e-mail qui serait valide et rejeté.

email = ~ /.+@[^@]+\.[^@]{2,}$/

broche
la source
3
C'est ce que je cherchais. Pas très restrictif, mais s'assure qu'il n'y a que 1 @ (car nous analysons une liste et voulons nous assurer qu'il n'y a pas de virgule manquante). Pour info, vous pouvez avoir un @ sur la gauche s'il est entre guillemets: Valid_email_addresses , mais c'est assez marginal.
Josh
2
Après l'avoir utilisé, j'ai réalisé que cela ne fonctionnait pas exactement. /^[^@]+@[^@]+\.[^@]{2}[^@]*$/ vérifie réellement le signe 1 @. Votre expression régulière laissera passer plusieurs fois à cause du. * À la fin.
Josh
1
Droite. Je n'essaie pas de rejeter tous les non valides, juste de ne pas rejeter une adresse e-mail valide.
broche
1
Il vaudrait bien mieux utiliser ceci: /^[^@]+@[^@]+\.[^@]{2,4}$/s'assurer qu'il se termine par 2 à 4 caractères non @. Comme l'a souligné @Josh, il permet désormais un @ supplémentaire à la fin. Mais vous pouvez également changer cela en: /^[^@]+@[^@]+\.[^a-z-A-Z]{2,4}$/puisque tous les domaines de premier niveau sont des caractères aZ. vous pouvez remplacer le 4par 5ou plus, permettant ainsi aux noms de domaine de premier niveau d'être plus longs à l'avenir.
FLY
@FLY, ka @ foo. renvoie correct. Est-il censé le faire, selon les normes?
SexyBeast
29

Vous pouvez utiliser celui utilisé par le plugin jQuery Validation:

/^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i
le chaos
la source
cela semble faire du bon travail. Cela a permis: a-b'[email protected]mais a pu a-b'[email protected]a-b'[email protected]
détecter
25

Pour l'évaluation la plus complète de la meilleure expression régulière pour valider une adresse e-mail, veuillez consulter ce lien; " Comparaison des adresses e-mail de validation des expressions régulières "

Voici l'expression top actuelle à des fins de référence:

/^([\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~]+\.)*[\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~]+@((((([a-z0-9]{1}[a-z0-9\-]{0,62}[a-z0-9]{1})|[a-z])\.)+[a-z]{2,6})|(\d{1,3}\.){3}\d{1,3}(\:\d{1,5})?)$/i
Eric Schoonover
la source
spoon16: Ce lien n'est pas vraiment correct. Sa déclaration selon laquelle il ne peut y avoir de modèle parfait pour valider les adresses e-mail est manifestement une faute. Vous pouvez , mais vous devez vous assurer que vous suivez le RFC jusqu'à la lettre. Et vous devez également choisir le bon RFC.
tchrist
Le "meilleur" en ce moment ne fonctionne pas avec l'expression régulière java - même après avoir correctement échappé et converti la chaîne.
Eric Chen
23

Sans oublier que les noms de domaine non latins (chinois, arabe, grec, hébreu, cyrillique, etc.) doivent être autorisés dans un proche avenir . Tout le monde doit changer l'expression rationnelle utilisée pour les e-mails, car ces caractères ne doivent certainement pas être couverts par [a-z]/ini \w. Ils échoueront tous.

Après tout, la meilleure façon de valider l'adresse e-mail est toujours d' envoyer réellement un e-mail à l'adresse en question pour valider l'adresse. Si l'adresse e-mail fait partie de l'authentification des utilisateurs (inscription / connexion / etc), vous pouvez parfaitement la combiner avec le système d'activation des utilisateurs. C'est-à-dire envoyer un e-mail avec un lien avec une clé d'activation unique à l'adresse e-mail spécifiée et autoriser la connexion uniquement lorsque l'utilisateur a activé le compte nouvellement créé en utilisant le lien dans l'e-mail.

Si le but de l'expression régulière est simplement d'informer rapidement l'utilisateur dans l'interface utilisateur que l'adresse e-mail spécifiée ne ressemble pas au bon format, le mieux est encore de vérifier si elle correspond fondamentalement à l'expression régulière suivante:

^([^.@]+)(\.[^.@]+)*@([^.@]+\.)+([^.@]+)$

Aussi simple que cela. Pourquoi diable vous soucieriez-vous des caractères utilisés dans le nom et le domaine? Il est de la responsabilité du client d'entrer une adresse e-mail valide, pas celle du serveur. Même lorsque le client entre une adresse e-mail syntaxiquement valide comme [email protected], cela ne garantit pas qu'il s'agit d'une adresse e-mail légitime. Aucun regex ne peut couvrir cela.

BalusC
la source
4
Je suis d'accord que l'envoi d'un message d'authentification est généralement le meilleur moyen pour ce genre de choses, syntaxiquement correct et valide ne sont pas les mêmes. Je suis frustré quand je suis obligé de taper mon adresse e-mail deux fois pour "Confirmation" comme si je ne pouvais pas regarder ce que j'avais tapé. Je ne copie de toute façon que le premier au second, il semble de plus en plus utilisé.
PeteT
se mettre d'accord! mais ce regex je ne pense pas est valide car il permet spacesaprès le @.eg. [email protected] com netest considéré comme un e-mail valide en utilisant l'expression rationnelle ci-dessus, alors qu'il devrait être non valide.
CB4
20

La spécification HTML5 suggère une expression régulière simple pour valider les adresses e-mail:

/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/

Cela n'est pas intentionnellement conforme à la RFC 5322 .

Remarque: Cette exigence est une violation délibérée de la RFC 5322 , qui définit une syntaxe pour les adresses de messagerie qui est à la fois trop stricte (avant le @caractère), trop vague (après le @caractère) et trop laxiste (autorisant les commentaires, les espaces, et cite des chaînes de manières inconnues de la plupart des utilisateurs) pour être utile ici.

La longueur totale pourrait également être limitée à 254 caractères, selon les errata RFC 3696 1690 .

Ross Allan
la source
Meilleure réponse! Voici un lien vers la recommandation w3: w3.org/TR/html5/forms.html#valid-e-mail-address Cette expression régulière est adoptée par de nombreux navigateurs.
Ryan Taylor
3
Ce n'est donc PAS la meilleure réponse! Ce modèle correspond à cette adresse totalement invalide: invalid@emailaddress. Je vous conseille de faire preuve de prudence et de nombreux tests avant de l'utiliser!
Sheridan
@Sheridan, si vous pensez qu'il y a un problème avec la spécification HTML5, vous pouvez soulever un problème ici: github.com/w3c/html/issues
Luna
Cela n'ajoute pas grand-chose à stackoverflow.com/a/8829363 et serait à mon humble avis mieux en tant que modification ou commentaire à ce sujet.
exemple @ localhost est valide, mais pour une application du monde réel, vous voudrez peut-être appliquer une extension de domaine, tout ce que vous devez faire est de changer la finale * en a + pour y parvenir (changer cette partie du modèle de 0+ à 1+ )
Mitch Satchwell
15

Pour une démonstration vivante, le monstre suivant est assez bon mais ne reconnaît toujours pas correctement toutes les adresses e-mail syntaxiquement valides: il reconnaît les commentaires imbriqués jusqu'à quatre niveaux de profondeur.

Il s'agit d'un travail pour un analyseur, mais même si une adresse est syntaxiquement valide, elle peut ne pas être livrable. Parfois, vous devez recourir à la méthode Hillbilly de "Hé, vous tous, regardez-nous!"

// derivative of work with the following copyright and license:
// Copyright (c) 2004 Casey West.  All rights reserved.
// This module is free software; you can redistribute it and/or
// modify it under the same terms as Perl itself.

// see http://search.cpan.org/~cwest/Email-Address-1.80/

private static string gibberish = @"
(?-xism:(?:(?-xism:(?-xism:(?-xism:(?-xism:(?-xism:(?-xism:\
s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^
\x0A\x0D]))|(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+))
|(?-xism:\\(?-xism:[^\x0A\x0D]))|)+)*\s*\)\s*))+)*\s*\)\s*)+
|\s+)*[^\x00-\x1F\x7F()<>\[\]:;@\,.<DQ>\s]+(?-xism:(?-xism:\
s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^
\x0A\x0D]))|(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+))
|(?-xism:\\(?-xism:[^\x0A\x0D]))|)+)*\s*\)\s*))+)*\s*\)\s*)+
|\s+)*)|(?-xism:(?-xism:(?-xism:\s*\((?:\s*(?-xism:(?-xism:(
?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|(?-xism:\s*\((?
:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x
0D]))|)+)*\s*\)\s*))+)*\s*\)\s*)+|\s+)*<DQ>(?-xism:(?-xism:[
^\\<DQ>])|(?-xism:\\(?-xism:[^\x0A\x0D])))+<DQ>(?-xism:(?-xi
sm:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xis
m:[^\x0A\x0D]))|(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\
]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|)+)*\s*\)\s*))+)*\s*\)\
s*)+|\s+)*))+)?(?-xism:(?-xism:(?-xism:\s*\((?:\s*(?-xism:(?
-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|(?-xism:
\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[
^\x0A\x0D]))|)+)*\s*\)\s*))+)*\s*\)\s*)+|\s+)*<(?-xism:(?-xi
sm:(?-xism:(?-xism:(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^(
)\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|(?-xism:\s*\((?:\s*(
?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))
|)+)*\s*\)\s*))+)*\s*\)\s*)+|\s+)*(?-xism:[^\x00-\x1F\x7F()<
>\[\]:;@\,.<DQ>\s]+(?:\.[^\x00-\x1F\x7F()<>\[\]:;@\,.<DQ>\s]
+)*)(?-xism:(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+))
|(?-xism:\\(?-xism:[^\x0A\x0D]))|(?-xism:\s*\((?:\s*(?-xism:
(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|)+)*\s
*\)\s*))+)*\s*\)\s*)+|\s+)*)|(?-xism:(?-xism:(?-xism:\s*\((?
:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x
0D]))|(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xi
sm:\\(?-xism:[^\x0A\x0D]))|)+)*\s*\)\s*))+)*\s*\)\s*)+|\s+)*
<DQ>(?-xism:(?-xism:[^\\<DQ>])|(?-xism:\\(?-xism:[^\x0A\x0D]
)))+<DQ>(?-xism:(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\
]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|(?-xism:\s*\((?:\s*(?-x
ism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|)+
)*\s*\)\s*))+)*\s*\)\s*)+|\s+)*))\@(?-xism:(?-xism:(?-xism:(
?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?
-xism:[^\x0A\x0D]))|(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^
()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|)+)*\s*\)\s*))+)*\s
*\)\s*)+|\s+)*(?-xism:[^\x00-\x1F\x7F()<>\[\]:;@\,.<DQ>\s]+(
?:\.[^\x00-\x1F\x7F()<>\[\]:;@\,.<DQ>\s]+)*)(?-xism:(?-xism:
\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[
^\x0A\x0D]))|(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+)
)|(?-xism:\\(?-xism:[^\x0A\x0D]))|)+)*\s*\)\s*))+)*\s*\)\s*)
+|\s+)*)|(?-xism:(?-xism:(?-xism:\s*\((?:\s*(?-xism:(?-xism:
(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|(?-xism:\s*\((
?:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\
x0D]))|)+)*\s*\)\s*))+)*\s*\)\s*)+|\s+)*\[(?:\s*(?-xism:(?-x
ism:[^\[\]\\])|(?-xism:\\(?-xism:[^\x0A\x0D])))+)*\s*\](?-xi
sm:(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:
\\(?-xism:[^\x0A\x0D]))|(?-xism:\s*\((?:\s*(?-xism:(?-xism:(
?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|)+)*\s*\)\s*))+
)*\s*\)\s*)+|\s+)*)))>(?-xism:(?-xism:\s*\((?:\s*(?-xism:(?-
xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|(?-xism:\
s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^
\x0A\x0D]))|)+)*\s*\)\s*))+)*\s*\)\s*)+|\s+)*))|(?-xism:(?-x
ism:(?-xism:(?-xism:(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^
()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|(?-xism:\s*\((?:\s*
(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D])
)|)+)*\s*\)\s*))+)*\s*\)\s*)+|\s+)*(?-xism:[^\x00-\x1F\x7F()
<>\[\]:;@\,.<DQ>\s]+(?:\.[^\x00-\x1F\x7F()<>\[\]:;@\,.<DQ>\s
]+)*)(?-xism:(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+)
)|(?-xism:\\(?-xism:[^\x0A\x0D]))|(?-xism:\s*\((?:\s*(?-xism
:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|)+)*\
s*\)\s*))+)*\s*\)\s*)+|\s+)*)|(?-xism:(?-xism:(?-xism:\s*\((
?:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\
x0D]))|(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-x
ism:\\(?-xism:[^\x0A\x0D]))|)+)*\s*\)\s*))+)*\s*\)\s*)+|\s+)
*<DQ>(?-xism:(?-xism:[^\\<DQ>])|(?-xism:\\(?-xism:[^\x0A\x0D
])))+<DQ>(?-xism:(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\
\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|(?-xism:\s*\((?:\s*(?-
xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|)
+)*\s*\)\s*))+)*\s*\)\s*)+|\s+)*))\@(?-xism:(?-xism:(?-xism:
(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(
?-xism:[^\x0A\x0D]))|(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[
^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|)+)*\s*\)\s*))+)*\
s*\)\s*)+|\s+)*(?-xism:[^\x00-\x1F\x7F()<>\[\]:;@\,.<DQ>\s]+
(?:\.[^\x00-\x1F\x7F()<>\[\]:;@\,.<DQ>\s]+)*)(?-xism:(?-xism
:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:
[^\x0A\x0D]))|(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+
))|(?-xism:\\(?-xism:[^\x0A\x0D]))|)+)*\s*\)\s*))+)*\s*\)\s*
)+|\s+)*)|(?-xism:(?-xism:(?-xism:\s*\((?:\s*(?-xism:(?-xism
:(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|(?-xism:\s*\(
(?:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A
\x0D]))|)+)*\s*\)\s*))+)*\s*\)\s*)+|\s+)*\[(?:\s*(?-xism:(?-
xism:[^\[\]\\])|(?-xism:\\(?-xism:[^\x0A\x0D])))+)*\s*\](?-x
ism:(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism
:\\(?-xism:[^\x0A\x0D]))|(?-xism:\s*\((?:\s*(?-xism:(?-xism:
(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|)+)*\s*\)\s*))
+)*\s*\)\s*)+|\s+)*))))(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?
>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|(?-xism:\s*\((?:
\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0
D]))|)+)*\s*\)\s*))+)*\s*\)\s*)*)"
  .Replace("<DQ>", "\"")
  .Replace("\t", "")
  .Replace(" ", "")
  .Replace("\r", "")
  .Replace("\n", "");

private static Regex mailbox =
  new Regex(gibberish, RegexOptions.ExplicitCapture); 
Greg Bacon
la source
12

Selon la norme officielle RFC 2822, l' expression régulière des e-mails valides est

(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])

si vous voulez l'utiliser en Java, c'est vraiment très facile

import java.util.regex.*;

class regexSample 
{
   public static void main(String args[]) 
   {
      //Input the string for validation
      String email = "[email protected]";

      //Set the email pattern string
      Pattern p = Pattern.compile(" (?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"
              +"(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21\\x23-\\x5b\\x5d-\\x7f]|\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])*\")"
                     + "@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21-\\x5a\\x53-\\x7f]|\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])+)\\]");

      //Match the given string with the pattern
      Matcher m = p.matcher(email);

      //check whether match is found 
      boolean matchFound = m.matches();

      if (matchFound)
        System.out.println("Valid Email Id.");
      else
        System.out.println("Invalid Email Id.");
   }
}
AZ_
la source
1
Votre expression régulière n'inclut pas la première lettre majuscule, par exemple [email protected], ce qui pourrait être gênant pour certains utilisateurs. Utilisez celui-ci à la place:(?:[A-Za-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[A-Za-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])
Kebab Krabby
@KebabKrabby Merci, veuillez modifier la réponse, j'accepte le changement.
AZ_
Si j'ajoute ce changement à votre réponse, ce ne sera plus le RFC 2822, donc je ne sais pas si c'est correct.
Kebab Krabby le
11

Voici le PHP que j'utilise. J'ai choisi cette solution dans l'esprit des "faux positifs valent mieux que les faux négatifs" comme déclaré par un autre commentateur ici ET en ce qui concerne le maintien de votre temps de réponse et la charge du serveur ... il n'y a vraiment pas besoin de gaspiller les ressources du serveur avec une expression régulière lorsque cela éliminera l'erreur utilisateur la plus simple. Vous pouvez toujours suivre cela en envoyant un e-mail de test si vous le souhaitez.

function validateEmail($email) {
  return (bool) stripos($email,'@');
}
Mac
la source
1
a) Le "gaspillage des ressources du serveur" est infinitésimal, mais si vous êtes si enclin, vous pouvez le faire côté client avec JS b) De quoi avez-vous besoin pour envoyer un e-mail d'enregistrement et l'utilisateur me saisit @ Forgotthedotcom? Votre «solution» échoue et vous perdez un utilisateur.
johnjohn
a) S'appuyer sur une validation JS qui échouerait lorsque JavaScript est désactivé ne semble pas non plus être la meilleure idée (juste btw)
auco
11

Norme RFC 5322:

Autorise la partie locale de l'atome point, la partie locale de chaîne entre guillemets, la partie locale obsolète (atome de point mélangé et la chaîne entre guillemets), le domaine de nom de domaine, le domaine littéral de domaine (adresse IPv4, IPv6 et IPv6 mappée IPv6), et (imbriqué) CFWS.

'/^(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){255,})(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){65,}@)((?>(?>(?>((?>(?>(?>\x0D\x0A)?[\t ])+|(?>[\t ]*\x0D\x0A)?[\t ]+)?)(\((?>(?2)(?>[\x01-\x08\x0B\x0C\x0E-\'*-\[\]-\x7F]|\\\[\x00-\x7F]|(?3)))*(?2)\)))+(?2))|(?2))?)([!#-\'*+\/-9=?^-~-]+|"(?>(?2)(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\x7F]))*(?2)")(?>(?1)\.(?1)(?4))*(?1)@(?!(?1)[a-z0-9-]{64,})(?1)(?>([a-z0-9](?>[a-z0-9-]*[a-z0-9])?)(?>(?1)\.(?!(?1)[a-z0-9-]{64,})(?1)(?5)){0,126}|\[(?:(?>IPv6:(?>([a-f0-9]{1,4})(?>:(?6)){7}|(?!(?:.*[a-f0-9][:\]]){8,})((?6)(?>:(?6)){0,6})?::(?7)?))|(?>(?>IPv6:(?>(?6)(?>:(?6)){5}:|(?!(?:.*[a-f0-9]:){6,})(?8)?::(?>((?6)(?>:(?6)){0,4}):)?))?(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?>\.(?9)){3}))\])(?1)$/isD'

Norme RFC 5321:

Autorise la partie locale à point atomique, la partie locale de chaîne entre guillemets, le domaine de nom de domaine et le domaine (IPv4, IPv6 et IPv4 mappé IPv6) domaine littéral domaine.

'/^(?!(?>"?(?>\\\[ -~]|[^"])"?){255,})(?!"?(?>\\\[ -~]|[^"]){65,}"?@)(?>([!#-\'*+\/-9=?^-~-]+)(?>\.(?1))*|"(?>[ !#-\[\]-~]|\\\[ -~])*")@(?!.*[^.]{64,})(?>([a-z0-9](?>[a-z0-9-]*[a-z0-9])?)(?>\.(?2)){0,126}|\[(?:(?>IPv6:(?>([a-f0-9]{1,4})(?>:(?3)){7}|(?!(?:.*[a-f0-9][:\]]){8,})((?3)(?>:(?3)){0,6})?::(?4)?))|(?>(?>IPv6:(?>(?3)(?>:(?3)){5}:|(?!(?:.*[a-f0-9]:){6,})(?5)?::(?>((?3)(?>:(?3)){0,4}):)?))?(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?>\.(?6)){3}))\])$/iD'

De base:

Permet la partie locale et le domaine de nom de domaine atomique (nécessitant au moins deux étiquettes de nom de domaine avec le TLD limité à 2 à 6 caractères alphabétiques).

"/^(?!.{255,})(?!.{65,}@)([!#-'*+\/-9=?^-~-]+)(?>\.(?1))*@(?!.*[^.]{64,})(?>[a-z0-9](?>[a-z0-9-]*[a-z0-9])?\.){1,126}[a-z]{2,6}$/iD"
MichaelRushton
la source
Quelle est la langue du diable qu'en ?? Je vois un /Ddrapeau, et vous l'avez cité avec des guillemets simples, mais vous avez également utilisé des barres obliques pour délimiter le motif? Ce n'est pas Perl, et ce ne peut pas être PCRE. Est-ce donc PHP? Je crois que ce sont les trois seuls qui permettent la récursivité comme (?1).
tchrist
C'est en PHP, qui utilise PCRE. Les barres obliques sont utilisées uniquement pour délimiter les caractères spéciaux tels que les parenthèses, les crochets et bien sûr les barres obliques et les guillemets simples. Le drapeau / D, si vous ne le saviez pas, sert à empêcher l'ajout d'une nouvelle ligne à la fin de la chaîne, ce qui serait autorisé autrement.
MichaelRushton
9

Étrange que vous ne puissiez pas autoriser des TLD à 4 caractères. Vous interdisez les utilisateurs de .info et .name , et la limitation de longueur arrête .travel et .museum , mais oui, ils sont moins courants que les TLD à 2 caractères et les TLD à 3 caractères.

Vous devez également autoriser les alphabets majuscules. Les systèmes de messagerie normaliseront la partie locale et la partie domaine.

Pour votre expression régulière de la partie domaine, le nom de domaine ne peut pas commencer par «-» et ne peut pas se terminer par «-». Dash ne peut que rester entre les deux.

Si vous avez utilisé la bibliothèque PEAR, consultez leur fonction de messagerie (oublié le nom exact / bibliothèque). Vous pouvez valider l'adresse e-mail en appelant une fonction, et cela valide l'adresse e-mail conformément à la définition dans RFC822.

Joseph Yee
la source
2
@Joseph Yee: La RFC 822 n'est-elle pas un peu datée?
tchrist
8
public bool ValidateEmail(string sEmail)
{
    if (sEmail == null)
    {
        return false;
    }

    int nFirstAT = sEmail.IndexOf('@');
    int nLastAT = sEmail.LastIndexOf('@');

    if ((nFirstAT > 0) && (nLastAT == nFirstAT) && (nFirstAT < (sEmail.Length - 1)))
    {
        return (Regex.IsMatch(sEmail, @"^[a-z|0-9|A-Z]*([_][a-z|0-9|A-Z]+)*([.][a-z|0-9|A-Z]+)*([.][a-z|0-9|A-Z]+)*(([_][a-z|0-9|A-Z]+)*)?@[a-z][a-z|0-9|A-Z]*\.([a-z][a-z|0-9|A-Z]*(\.[a-z][a-z|0-9|A-Z]*)?)$"));
    }
    else
    {
        return false;
    }
}
Murthy Jeedigunta
la source