¿Cómo validar una dirección de correo electrónico utilizando una expresión regular?

3316

A lo largo de los años, he desarrollado lentamente una expresión regular que valida la mayoría de las direcciones de correo electrónico correctamente, suponiendo que no usen una dirección IP como parte del servidor.

Lo uso en varios programas PHP y funciona la mayor parte del tiempo. Sin embargo, de vez en cuando me contacta alguien que tiene problemas con un sitio que lo usa, y termino teniendo que hacer algunos ajustes (más recientemente me di cuenta de que no estaba permitiendo TLD de 4 caracteres).

¿Cuál es la mejor expresión regular que tiene o ha visto para validar correos electrónicos?

He visto varias soluciones que usan funciones que usan varias expresiones más cortas, pero prefiero tener una expresión larga y compleja en una función simple en lugar de varias expresiones cortas en una función más compleja.

acrosman
fuente
55
La expresión regular que puede validar que un IDNA está formateado correctamente no cabe en stackexchange. (las reglas sobre canonicalización son realmente tortuosas y particularmente inadecuadas para el procesamiento de expresiones regulares)
Jasen
Las expresiones regulares pueden ser variables, ya que en algunos casos, una estafa de correo electrónico puede contener un espacio y, en otras ocasiones, no puede contener espacios.
Ṃųỻịgǻňạcểơửṩ

Respuestas:

2440

La expresión regular totalmente compatible con RFC 822 es ineficiente y oscura debido a su longitud. Afortunadamente, RFC 822 fue reemplazado dos veces y la especificación actual para las direcciones de correo electrónico es RFC 5322 . RFC 5322 conduce a una expresión regular que se puede entender si se estudia durante unos minutos y es lo suficientemente eficiente para el uso real.

Se puede encontrar una expresión regular compatible con RFC 5322 en la parte superior de la página en http://emailregex.com/ pero utiliza el patrón de dirección IP que flota en Internet con un error que permite 00cualquiera de los valores decimales de byte sin signo en un dirección delimitada por puntos, que es ilegal. El resto parece ser coherente con la gramática RFC 5322 y pasa varias pruebas usando grep -Po, incluidos los casos nombres de dominio, direcciones IP, incorrectos y nombres de cuenta con y sin comillas.

Al corregir el 00error en el patrón de IP, obtenemos una expresión regular que funciona y bastante rápido. (Raspe la versión renderizada, no la rebaja, para el código real).

(?: [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]) +) \])

o:

(?:[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])+)\])

Aquí hay un diagrama de la máquina de estados finitos para la expresión regular anterior que es más clara que la propia expresión regular ingrese la descripción de la imagen aquí

Los patrones más sofisticados en Perl y PCRE (biblioteca de expresiones regulares usadas, por ejemplo, en PHP) pueden analizar correctamente RFC 5322 sin problemas . Python y C # también pueden hacer eso, pero usan una sintaxis diferente de las dos primeras. Sin embargo, si se ve obligado a usar uno de los muchos lenguajes de coincidencia de patrones menos potentes, entonces es mejor usar un analizador real.

También es importante comprender que validarlo según el RFC no le dice absolutamente nada acerca de si esa dirección realmente existe en el dominio suministrado, o si la persona que ingresa la dirección es su verdadero propietario. Las personas inscriben a otros en las listas de correo de esta manera todo el tiempo. Una corrección que requiere un tipo de validación más elegante que implica enviar a esa dirección un mensaje que incluye un token de confirmación destinado a ser ingresado en la misma página web que la dirección.

Los tokens de confirmación son la única forma de saber que recibió la dirección de la persona que lo ingresó. Es por eso que la mayoría de las listas de correo ahora usan ese mecanismo para confirmar las suscripciones. Después de todo, cualquiera puede menospreciar [email protected], y eso incluso se considerará legal, pero no es probable que sea la persona del otro lado.

Para PHP, usted debe no utilizar el patrón dado en Validar una dirección de correo electrónico con PHP, de la manera correcta a partir del cual cito:

Existe cierto peligro de que el uso común y la codificación descuidada generalizada establezcan un estándar de facto para las direcciones de correo electrónico que sea más restrictivo que el estándar formal registrado.

Eso no es mejor que todos los otros patrones no RFC. Ni siquiera es lo suficientemente inteligente como para manejar incluso RFC 822 , y mucho menos RFC 5322. Sin embargo, este sí lo es.

Si quieres ponerte elegante y pedante, implementa un motor de estado completo . Una expresión regular solo puede actuar como un filtro rudimentario. El problema con las expresiones regulares es que decirle a alguien que su dirección de correo electrónico perfectamente válida no es válida (un falso positivo) porque su expresión regular no puede manejarlo es grosero y descortés desde la perspectiva del usuario. Un motor de estado para este propósito puede validar e incluso corregir direcciones de correo electrónico que de otro modo se considerarían inválidas, ya que desmonta la dirección de correo electrónico de acuerdo con cada RFC. Esto permite una experiencia potencialmente más agradable, como

La dirección de correo electrónico especificada 'myemail @ address, com' no es válida. ¿Quiso decir '[email protected]'?

Consulte también Validar direcciones de correo electrónico , incluidos los comentarios. O comparando la dirección de correo electrónico validando expresiones regulares .

Visualización de expresiones regulares

Demo de Debuggex

bortzmeyer
fuente
180
Dijiste "No hay una buena expresión regular". ¿Es esto general o específico para la validación de la dirección de correo electrónico?
Tomalak
37
@Tomalak: solo para direcciones de correo electrónico. Como dijo bortzmeyer, la RFC es extremadamente complicada
Luk
37
El artículo de Linux Journal que mencionas es, de hecho, erróneo en varios aspectos. En particular, Lovell claramente no ha leído las erratas del RFC3696 y repite algunos de los errores en la versión publicada del RFC. Más aquí: dominicsayers.com/isemail
Dominic Sayers
99
Jeff Atwood tiene una expresión regular encantadora en esta publicación de blog para validar todas las direcciones de correo electrónico válidas: codinghorror.com/blog/2005/02/regex-use-vs-regex-abuse.html
CMircea
55
Tenga en cuenta que la especificación HTML5 actual incluye una expresión regular y ABNF para la validación de entrada de tipo de correo electrónico que es deliberadamente más restrictiva que las RFC originales.
Sincronización
747

No debe usar expresiones regulares para validar las direcciones de correo electrónico.

En su lugar, use la clase MailAddress , así:

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

La MailAddressclase utiliza un analizador BNF para validar la dirección de acuerdo con RFC822.

Si planea usar MailAddresspara validar la dirección de correo electrónico, tenga en cuenta que este enfoque acepta también la parte del nombre para mostrar de la dirección de correo electrónico, y eso puede no ser exactamente lo que desea lograr. Por ejemplo, acepta estas cadenas como direcciones de correo electrónico válidas:

En algunos de estos casos, solo la última parte de las cadenas se analiza como la dirección; el resto antes de eso es el nombre para mostrar. Para obtener una dirección de correo electrónico sin nombre para mostrar, puede verificar la dirección normalizada con su cadena original.

bool isValid = false;

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

Además, user@company.MailAddress también acepta una dirección que tenga un punto al final .

Si realmente quieres usar una expresión regular, aquí está :

(?: (?: \ 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
fuente
26
Encontrará que la clase MailAddress en .NET 4.0 es mucho mejor para validar direcciones de correo electrónico que en versiones anteriores. Le hice algunas mejoras significativas.
Jeff Tucker
77
Creo que de alguna manera ... no funciona ... para identificadores más simples. a @ b no valida. [email protected] coincide solo hasta que ar @ b, .com no coincide. Sin embargo, algo como "Yo soy yo" @ [10.10.10.10] funciona. :)
Raze
55
Tenga en cuenta que estos validadores de expresiones regulares que cumplen con RFC dejarán pasar muchas direcciones de correo electrónico que probablemente no desee aceptar, como "a <body / onload = alert (' lol.com?'+document.cookies ) @aa> "que es una dirección de correo electrónico válida en Perl's Email :: Valid (que usa esa enorme expresión regular), y puede ser explotada para XSS rt.cpan.org/Public/Bug/Display.html?id=75650
Matthew Lock
99
@MatthewLock: Eso no es peor que [email protected]. No debe confiar en la validación de correo electrónico para evitar XSS.
SLaks
10
@MatthewLock: No. Usted necesidad de escapar de consultas SQL (o, mejor aún, parámetros de uso). La desinfección no es una defensa adecuada.
SLaks
536

Esta pregunta se hace mucho, pero creo que deberías dar un paso atrás y preguntarte por qué quieres validar sintácticamente las direcciones de correo electrónico. ¿Cuál es el beneficio realmente?

  • No detectará errores tipográficos comunes.
  • No evita que las personas ingresen direcciones de correo electrónico no válidas o inventadas, o que ingresen la dirección de otra persona.

Si desea validar que un correo electrónico es correcto, no tiene más remedio que enviar un correo electrónico de confirmación y que el usuario responda a eso. En muchos casos, usted tiene que enviar un correo de confirmación de todos modos por razones de seguridad o por razones éticas (por lo que no se puede por ejemplo, alguien de registro a un servicio en contra de su voluntad).

JacquesB
fuente
92
Puede valer la pena verificar que ingresaron algo @ algo en el campo en una validación del lado del cliente solo para detectar errores simples, pero en general tiene razón.
Martin Beckett
8
Martin, te di un +1, solo para leer más tarde que foobar @ dk es un correo electrónico válido. No sería bonito, pero si desea cumplir con RFC Y usar el sentido común, debe detectar casos como este y pedirle al usuario que confirme que es correcto.
philfreo
106
@olavk: si alguien ingresa un error tipográfico (por ejemplo:) me@hotmail, obviamente no recibirá su correo electrónico de confirmación, y luego ¿dónde están? Ya no están en su sitio y se preguntan por qué no pudieron registrarse. En realidad no, no lo están, se han olvidado por completo de ti. Sin embargo, si pudieras hacer una comprobación de cordura básica con una expresión regular mientras todavía están contigo, entonces pueden detectar ese error de inmediato y tienes un usuario feliz.
nickf
55
@JacquesB: Haces un excelente punto. El hecho de que sea aprobado por el RFC no significa que realmente sea la dirección de ese usuario. De lo contrario, todas esas [email protected]direcciones indican un comandante en jefe muy ocupado. :)
tchrist el
39
No tiene que ser blanco o negro. Si el correo electrónico parece incorrecto, avísele al usuario. Si el usuario aún quiere continuar, déjelo. No obligue al usuario a ajustarse a su expresión regular, más bien, use la expresión regular como herramienta para ayudar al usuario a saber que puede haber un error.
ninjaneer
354

Todo depende de cuán preciso quieras ser. Para mis propósitos, donde solo estoy tratando de evitar cosas como bob @ aol.com(espacios en los correos electrónicos) o steve(sin dominio) o mary@aolcom(sin período antes de .com), uso

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

Claro, coincidirá con cosas que no son direcciones de correo electrónico válidas, pero se trata de obtener errores simples comunes.

Hay varios cambios que se pueden hacer a esa expresión regular (y algunos están en los comentarios para esta respuesta), pero es simple y fácil de entender, y es un buen primer intento.

Andy Lester
fuente
66
No coincide con foobar @ dk, que es una dirección de correo electrónico válida y funcional (aunque probablemente la mayoría de los servidores de correo no lo acepten o agregarán
algo.com
3
Sí lo hará Te sugiero que lo pruebes tú mismo. $ perl -le'print q{[email protected]} = ~ /^\S+@\S+\.\S+$/? q {Y}: q {N} '
Andy Lester el
77
@ Richard: .está incluido en \S.
David Thornley
43
JJJ: Sí, coincidirá con mucha basura. Coincidirá con & $ * # $ (@ $ 0 (%)) $ #.) & *) (* $, También. Para mí, estoy más preocupado por atrapar el error tipográfico de dedos sueltos como si mary@aolcomfuera basura completa . YMMV.
Andy Lester
55
Solo para controlar las @señales: /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/ jsfiddle.net/b9chris/mXB96
Chris Moschini
338

Depende de lo que quieras decir con mejor: si estás hablando de atrapar cada dirección de correo electrónico válida, utiliza lo siguiente:

(?:(?:\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 está buscando algo más simple pero que atrapará las direcciones de correo electrónico más válidas, intente algo como:

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

EDITAR: desde el enlace:

Esta expresión regular solo validará direcciones que hayan tenido algún comentario eliminado y reemplazado con espacios en blanco (esto lo hace el módulo).

Buena persona
fuente
10
No coincide con todas las direcciones, algunas deben transformarse primero. Desde el enlace: "Esta expresión regular solo validará las direcciones que hayan tenido algún comentario eliminado y reemplazado con espacios en blanco (esto lo hace el módulo)".
Chas. Owens
47
¿Me puede dar un ejemplo de algunos email addressque pasen erróneamente por el segundo, pero sean atrapados por la expresión regular más larga?
Lazer
44
Aunque alguna vez me encantó, es un validador RFC 822, no un RFC 5322 .
tchrist el
24
@Lazer in..valid @ example.com sería un ejemplo simple. No está permitido tener dos puntos consecutivos sin comillas en la parte local.
Randal Schwartz
55
@Mikhail perl pero en realidad no deberías usarlo.
Buena persona
287

[ACTUALIZADO] He recopilado todo lo que sé sobre la validación de direcciones de correo electrónico aquí: http://isemail.info , que ahora no solo valida sino que también diagnostica problemas con las direcciones de correo electrónico. Estoy de acuerdo con muchos de los comentarios aquí que la validación es solo una parte de la respuesta; vea mi ensayo en http://isemail.info/about .

is_email () sigue siendo, hasta donde yo sé, el único validador que le dirá definitivamente si una cadena dada es una dirección de correo electrónico válida o no. Subí una nueva versión en http://isemail.info/

Cotejé casos de prueba de Cal Henderson, Dave Child, Phil Haack, Doug Lovell, RFC5322 y RFC 3696. 275 direcciones de prueba en total. Ejecuté todas estas pruebas contra todos los validadores gratuitos que pude encontrar.

Intentaré mantener esta página actualizada a medida que las personas mejoren sus validadores. Gracias a Cal, Michael, Dave, Paul y Phil por su ayuda y cooperación en la compilación de estas pruebas y críticas constructivas de mi propio validador .

Las personas deben ser conscientes de la errata contra RFC 3696 en particular. Tres de los ejemplos canónicos son, de hecho, direcciones no válidas. Y la longitud máxima de una dirección es de 254 o 256 caracteres, no 320.

Dominic Sayers
fuente
Este validador también parece correcto. [... el tiempo pasa ...] Hm, parece que es solo RFC 5322, no 3693 o erratas al respecto.
tchrist
1
Muy agradable. Aquí no solo obtenemos un buen ensayo, también obtenemos un comprobador de validación y una biblioteca para descargar. ¡Buena respuesta!
bgmCoder
Su validador no es compatible con punycode (RFC 3492). name@öäü.at puede ser una dirección válida. (se traduce como [email protected])
Josef dice Reinstate Monica
Hola @ Josef. Debe intentar validar [email protected]ya que este código se trata de validación, no de interpretación. Si desea agregar un traductor de punycode, me complace aceptar una solicitud de extracción en github.com/dominicsayers/isemail
Dominic Sayers
266

Según la especificación HTML5 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])?)*$

Contexto:

Una dirección de correo electrónico válida es una cadena que coincide con la producción de ABNF [...].

Nota: Este requisito es una violación intencional de RFC 5322 , que define una sintaxis para las direcciones de correo electrónico que es simultáneamente demasiado estricta (antes del carácter "@"), demasiado vaga (después del carácter "@") y demasiado laxa ( Permitir que los comentarios, los caracteres de espacios en blanco y las cadenas citadas de maneras desconocidas para la mayoría de los usuarios sean de utilidad práctica aquí.

La siguiente expresión regular compatible con JavaScript y Perl es una implementación de la definición anterior.

/^[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
fuente
12
Esto es interesante. Es una violación de RFC, pero intencional y produce sesne. Ejemplo del mundo real: gmail ignora los puntos en la parte anterior a @, por lo que si su correo electrónico es [email protected] puede enviar correos electrónicos a test. @ Gmail.com o test .... @ gmail.com, ambas direcciones son inválido según RFC, pero válido en el mundo real.
valentinas
Creo que la última parte debería ser '+' en lugar de '*': ^ [a-zA-Z0-9.! # $% & '* + / =? ^ _ `{|} ~ -] + @ [a- zA-Z0-9 -] + (?: \. [a-zA-Z0-9 -] +) + $
mmmmmm
77
@mmmmmm john.doe@localhostes válido. Por supuesto, en una aplicación del mundo real (es decir, una comunidad), me gustaría que sugiera reemplazar * por +
rabudde
3
@valentinas En realidad, el RFC no excluye estas partes locales, pero deben ser citadas. "test...."@gmail.comes perfectamente válido según el RFC y semánticamente equivalente a [email protected].
Rinke
Recibo un error al intentar enviar un correo electrónico usando Python a través del relé de mi empresa si intento enviarlo a una dirección con un. @ O .. @. En realidad, ese también es el caso con una _ @. Prefiero eliminarlos antes de enviar que confiar en que el destinatario lo hará.
ndvo
201

Es fácil en Perl 5.10 o posterior:

/(?(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
fuente
20
Me encantaría ver esto en Python
tdc
44
Creo que solo un subconjunto de la addrspecparte es realmente relevante para la pregunta. Aceptar más que eso y reenviarlo a través de alguna otra parte del sistema que no está lista para aceptar direcciones RFC5822 completas es como disparar es su propio pie.
dolmen
3
Genial (+1) pero técnicamente no es una expresión regular, por supuesto ... (lo que sería imposible ya que la gramática no es regular).
Rinke
10
las expresiones regulares dejaron de ser regulares hace algún tiempo. ¡Sin embargo, es un Perge 'regex' válido!
rjh
44
Configuré una prueba para esta expresión regular en IDEone: ideone.com/2XFecH Sin embargo, no es justo "perfectamente". ¿A alguien le importaría sonar? ¿Me estoy perdiendo de algo?
Mike
159

yo suelo

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

Cuál es el utilizado en ASP.NET por el RegularExpressionValidator.

por Hornshøj-Schierbeck
fuente
28
¡Abucheo! Mi dirección (mal aconsejada) [email protected]es rechazada.
Phrogz
3
De acuerdo con esta página data.iana.org/TLD/tlds-alpha-by-domain.txt no hay dominios con un solo carácter en el nivel superior, por ejemplo, "something.c", "something.a", aquí está la versión que admite al menos 2 caracteres: "something.pl", "something.us":^\\w+([-+.']\\w+)*@\\w+([-.]\\w+)*\\.\\w{2,}([-.]\\w+)*$
Tomasz Szulc
44
@Wayne Whitty. Se ha topado con el problema principal de atender la gran mayoría de las direcciones, o TODAS, incluidas las que nadie usaría, excepto para probar la validación del correo electrónico.
Patanjali
La barra diagonal inversa adicional de @TomaszSzulc en su respuesta es confusa, simplemente la corregí y el soporte de nombres de dominios de 2 caracteres funciona, ^ \ w + ([- +. '] \ W +) * @ \ w + ([-.] \ W +) * \. \ w {2,} ([-.] \ w +) * $
Aqib Mumtaz
2
esto falla en lo [email protected]que de hecho es válido (un cliente nuestro tenía una dirección similar) `
Simon_Weaver
142

No sé cuál es el mejor, pero este es al menos correcto, siempre y cuando las direcciones tengan sus comentarios eliminados y reemplazados por espacios en blanco.

Seriamente. Debe usar una biblioteca ya escrita para validar correos electrónicos. Probablemente, la mejor manera sea enviar un correo electrónico de verificación a esa dirección.

Christian Vest Hansen
fuente
2
Hasta donde yo sé, algunas bibliotecas también están equivocadas. Recuerdo vagamente que PHP PEAR tenía ese error.
bortzmeyer
Esa página también tiene un descargo de responsabilidad en la parte inferior sobre un par de cosas de la especificación. que la expresión regular no es compatible.
Chris Vest
77
Esa es una especificación RFC 822, no una especificación RFC 5322 .
tchrist
12
En última instancia, tiene razón en que la única forma de validar verdaderamente una dirección de correo electrónico es enviarle un correo electrónico y esperar una respuesta.
Blazemonger
109

Las direcciones de correo electrónico que quiero validar serán utilizadas por una aplicación web ASP.NET utilizando el espacio de nombres System.Net.Mail para enviar correos electrónicos a una lista de personas. Entonces, en lugar de usar una expresión regular muy compleja, solo trato de crear una instancia de MailAddress desde la dirección. El constructor MailAddress lanzará una excepción si la dirección no se forma correctamente. De esta manera, sé que al menos puedo sacar el correo electrónico de la puerta. Por supuesto, esta es la validación del lado del servidor, pero como mínimo lo necesita de todos modos.

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
fuente
3
Un buen punto Incluso si esta validación del servidor rechaza alguna dirección válida, entonces no es un problema, ya que de todos modos no podrá enviar a esta dirección utilizando esta tecnología de servidor en particular. O puede intentar hacer lo mismo utilizando cualquier biblioteca de correo electrónico de terceros que use en lugar de las herramientas predeterminadas.
Usuario
Realmente me gusta cómo esto aprovecha el código de marco .Net, no tiene sentido reinventar la rueda. Esto es excelente. Simple, limpio y asegura que realmente puede enviar el correo electrónico. Buen trabajo.
Cory House
... sí, y para aquellos interesados ​​en cómo se valida, eche un vistazo al código en Reflector, hay bastante, ¡y no es una expresión regular!
Tom Carter
2
Solo una nota: la clase MailAddress no coincide con RFC5322, si solo desea usarlo para la validación (y no enviar también, en cuyo caso es un punto discutible como se mencionó anteriormente). Ver: stackoverflow.com/questions/6023589/…
porges
Solo un problema menor: si desea hacer que su código de validación del lado del servidor sea más reutilizable (ya sea en este caso o en general), sugiero usar en args.Valuelugar de hacer referencia al campo como txtEmail.Textcodificado. El último vinculará su validador a la única instancia de control, que puede estar bien, siempre que tenga un solo campo de correo electrónico, pero no se recomienda lo contrario.
pholpar
109

Respuesta rápida

Use la siguiente expresión regular para la validación de entrada:

([-!#-'*+/-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])?)+

Direcciones que coinciden con esta expresión regular:

  • tener una parte local (es decir, la parte anterior al signo @) que cumple estrictamente con RFC 5321/5322,
  • tener una parte de dominio (es decir, la parte después del signo @) que es un nombre de host con al menos dos etiquetas, cada una de las cuales tiene un máximo de 63 caracteres.

La segunda restricción es una restricción en RFC 5321/5322.

Respuesta elaborada

El uso de una expresión regular que reconozca las direcciones de correo electrónico podría ser útil en varias situaciones: por ejemplo, para buscar direcciones de correo electrónico en un documento, para validar la entrada del usuario o como una restricción de integridad en un repositorio de datos.

Sin embargo, debe tenerse en cuenta que si desea averiguar si la dirección realmente se refiere a un buzón existente, no hay sustituto para enviar un mensaje a la dirección. Si solo desea verificar si una dirección es gramaticalmente correcta, entonces podría usar una expresión regular, pero tenga en cuenta que ""@[]es una dirección de correo electrónico gramaticalmente correcta que ciertamente no se refiere a un buzón existente.

La sintaxis de las direcciones de correo electrónico se ha definido en varios RFC , especialmente RFC 822 y RFC 5322 . RFC 822 debe verse como el estándar "original" y RFC 5322 como el último estándar. La sintaxis definida en RFC 822 es la más indulgente y los estándares posteriores han restringido la sintaxis más y más, donde los sistemas o servicios más nuevos deberían reconocer la sintaxis obsoleta, pero nunca producirla.

En esta respuesta, tomaré "dirección de correo electrónico" addr-speccomo se define en los RFC (es decir [email protected], pero no "John Doe"<[email protected]>, ni some-group:[email protected],[email protected];).

Hay un problema al traducir las sintaxis RFC en expresiones regulares: ¡las sintaxis no son regulares! Esto se debe a que permiten comentarios opcionales en las direcciones de correo electrónico que se pueden anidar infinitamente, mientras que la anidación infinita no se puede describir mediante una expresión regular. Para buscar o validar direcciones que contengan comentarios, necesita un analizador o expresiones más potentes. (Tenga en cuenta que los lenguajes como Perl tienen construcciones para describir las gramáticas libres de contexto de una manera similar a la expresión regular). En esta respuesta, ignoraré los comentarios y solo consideraré las expresiones regulares adecuadas.

Los RFC definen sintaxis para mensajes de correo electrónico, no para direcciones de correo electrónico como tales. Las direcciones pueden aparecer en varios campos de encabezado y aquí es donde se definen principalmente. Cuando aparecen en los campos de encabezado, las direcciones pueden contener (entre tokens léxicos) espacios en blanco, comentarios e incluso saltos de línea. Sin embargo, semánticamente esto no tiene importancia. Al eliminar este espacio en blanco, etc. de una dirección, obtienes una representación canónica semánticamente equivalente . Por lo tanto, la representación canónica de first. last (comment) @ [3.5.7.9]es first.last@[3.5.7.9].

Se deben usar diferentes sintaxis para diferentes propósitos. Si desea escanear direcciones de correo electrónico en un documento (posiblemente muy antiguo), puede ser una buena idea usar la sintaxis como se define en RFC 822. Por otro lado, si desea validar la entrada del usuario, puede usar el sintaxis como se define en RFC 5322, probablemente solo acepte representaciones canónicas. Debe decidir qué sintaxis se aplica a su caso específico.

Utilizo expresiones regulares POSIX "extendidas" en esta respuesta, suponiendo un conjunto de caracteres compatible con ASCII.

RFC 822

Llegué a la siguiente expresión regular. Invito a todos a intentar romperlo. Si encuentra falsos positivos o falsos negativos, publíquelos en un comentario e intentaré corregir la expresión lo antes posible.

([^][()<>@,;:\\". \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)*]))*

Creo que es totalmente compatible con RFC 822, incluida la errata . Solo reconoce las direcciones de correo electrónico en su forma canónica. Para una expresión regular que reconoce espacios en blanco (plegables), vea la derivación a continuación.

La derivación muestra cómo llegué a la expresión. Enumero todas las reglas gramaticales relevantes del RFC exactamente como aparecen, seguido de la expresión regular correspondiente. Cuando se ha publicado una errata, doy una expresión separada para la regla gramatical corregida (marcada "errata") y uso la versión actualizada como subexpresión en las expresiones regulares posteriores.

Como se indica en el apartado 3.1.4. de RFC 822 se puede insertar un espacio en blanco lineal opcional entre las fichas léxicas. Donde corresponda, expandí las expresiones para acomodar esta regla y marqué el resultado con "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

Llegué a la siguiente expresión regular. Invito a todos a intentar romperlo. Si encuentra falsos positivos o falsos negativos, publíquelos en un comentario e intentaré corregir la expresión lo antes posible.

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

Creo que es totalmente compatible con RFC 5322, incluida la errata . Solo reconoce las direcciones de correo electrónico en su forma canónica. Para una expresión regular que reconoce espacios en blanco (plegables), vea la derivación a continuación.

La derivación muestra cómo llegué a la expresión. Enumero todas las reglas gramaticales relevantes del RFC exactamente como aparecen, seguido de la expresión regular correspondiente. Para las reglas que incluyen espacios en blanco semánticamente irrelevantes (plegables), doy una expresión regular separada marcada "(normalizada)" que no acepta este espacio en blanco.

Ignoré todas las reglas "obs-" del RFC. Esto significa que las expresiones regulares solo coinciden con las direcciones de correo electrónico que son estrictamente compatibles con RFC 5322. Si tiene que hacer coincidir las direcciones "antiguas" (como lo hace la gramática más flexible, incluidas las reglas "obs-"), puede usar una de las expresiones regulares RFC 822 del párrafo anterior.

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^-~]*])

Tenga en cuenta que algunas fuentes (especialmente w3c ) afirman que RFC 5322 es demasiado estricto en la parte local (es decir, la parte anterior al signo @). Esto se debe a que "..", "a..b" y "a". no son puntos-átomos válidos, mientras que pueden usarse como nombres de buzones. El RFC, sin embargo, no permiten partes locales como estos, excepto en que tienen que ser citado. Entonces, en lugar de [email protected]usted, debe escribir "a..b"@example.net, que es semánticamente equivalente.

Restricciones adicionales

SMTP (como se define en RFC 5321 ) restringe aún más el conjunto de direcciones de correo electrónico válidas (o en realidad: nombres de buzones). Parece razonable imponer esta gramática más estricta, de modo que la dirección de correo electrónico coincidente pueda usarse para enviar un correo electrónico.

RFC 5321 básicamente deja sola la parte "local" (es decir, la parte anterior al signo @), pero es más estricta en la parte del dominio (es decir, la parte posterior al signo @). Solo permite nombres de host en lugar de átomos de punto y literales de dirección en lugar de literales de dominio.

La gramática presentada en RFC 5321 es demasiado indulgente cuando se trata de nombres de host y direcciones IP. Me tomé la libertad de "corregir" las reglas en cuestión, utilizando este borrador y RFC 1034 como pautas. Aquí está la expresión regular resultante.

([-!#-'*+/-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^-~]+)])

Tenga en cuenta que, según el caso de uso, es posible que no desee permitir un "General-address-literal" en su expresión regular. También tenga en cuenta que utilicé una búsqueda anticipada negativa (?!IPv6:)en la expresión regular final para evitar que la parte "General-address-literal" coincida con direcciones IPv6 mal formadas. Algunos procesadores de expresiones regulares no son compatibles con la búsqueda anticipada negativa. Elimine la subcadena |(?!IPv6:)[0-9A-Za-z-]*[0-9A-Za-z]:[!-Z^-~]+de la expresión regular si desea eliminar toda la parte "General-address-literal".

Aquí está la derivación:

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^-~]+)])

Validación de entrada del usuario

Un caso de uso común es la validación de entrada del usuario, por ejemplo en un formulario html. En ese caso, generalmente es razonable excluir literales de dirección y requerir al menos dos etiquetas en el nombre de host. Tomando como base la expresión regular RFC 5321 mejorada de la sección anterior, la expresión resultante sería:

([-!#-'*+/-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])?)+

No recomiendo restringir aún más la parte local, por ejemplo, excluyendo las cadenas entre comillas, ya que no sabemos qué tipo de nombres de buzones permiten algunos hosts (como "a..b"@example.neto incluso "a b"@example.net).

Tampoco recomiendo validar explícitamente contra una lista de dominios literales de nivel superior o incluso imponer restricciones de longitud (recuerde cómo invalida ".museum" [a-z]{2,4}), pero si debe:

([-!#-'*+/-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 ...)

Asegúrese de mantener su expresión regular actualizada si decide seguir el camino de la validación explícita del dominio de nivel superior.

Consideraciones adicionales

Cuando solo se aceptan nombres de host en la parte del dominio (después del signo @), las expresiones regulares anteriores solo aceptan etiquetas con un máximo de 63 caracteres, como deberían. Sin embargo, no imponen el hecho de que el nombre completo del host debe tener como máximo 253 caracteres (incluidos los puntos). Aunque esta restricción estrictamente hablando sigue siendo regular, no es factible hacer una expresión regular que incorpore esta regla.

Otra consideración, especialmente cuando se usan expresiones regulares para la validación de entrada, es la retroalimentación al usuario. Si un usuario ingresa una dirección incorrecta, sería bueno dar un poco más de comentarios que una simple "dirección sintácticamente incorrecta". Con expresiones regulares "vainilla" esto no es posible.

Estas dos consideraciones podrían abordarse analizando la dirección. En algunos casos, la restricción de longitud adicional en los nombres de host también podría abordarse mediante el uso de una expresión regular adicional que lo verifique y que coincida la dirección con ambas expresiones.

Ninguna de las expresiones regulares en esta respuesta está optimizada para el rendimiento. Si el rendimiento es un problema, debería ver si (y cómo) se puede optimizar la expresión regular de su elección.

Rinke
fuente
3
RFC 6532 actualiza 5322 para permitir e incluir UTF-8 completo y limpio. Detalles adicionales aquí .
Según Wikipedia, parece que la parte local, cuando está punteada, tiene una limitación de 64 caracteres por parte, y también el RFC 5322 se refiere a la parte local punteada para ser interpretada con las restricciones de los dominios. Por ejemplo 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.comno debe validar. Sugiero cambiar los signos "+" en el primer grupo (nombre antes del punto opcional) y en el segundo grupo (nombre después de los siguientes puntos) a{1,64}
Xavi Montero
Como los comentarios tienen un tamaño limitado, aquí está la expresión regular resultante que planeo usar, que es la que se encuentra al comienzo de esta respuesta, además de limitar el tamaño en la parte local, además de agregar una barra diagonal inversa antes de "/" símbolo requerido por PHP y también en regex101.com: en PHP uso:$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
PRECAUCIÓN: Por alguna razón, StackOverflow agrega caracteres ocultos al copiar desde la reducción representada. Cópielo en regex101.com y verá puntos negros allí. Debe eliminarlos y corregir la cadena ... Tal vez si está integrado en la respuesta, allí se pueden copiar correctamente. Lo siento por los inconvenientes ocasionados. No quiero agregar una nueva respuesta ya que esta es la correcta. Además, no quiero editar directamente a menos que la comunidad piense que esto debería integrarse en él.
Xavi Montero
@XaviMontero ¡Gracias por contribuir con Xavi! ¿Tiene alguna referencia al RFC que indique el límite de 64 caracteres en las etiquetas de piezas locales? Si es así, con gusto ajustaría la respuesta.
Rinke
73

Hay muchos ejemplos de esto en la red (y creo que incluso uno que valida completamente el RFC, pero tiene decenas / cientos de líneas de largo si la memoria sirve). La gente tiende a dejarse llevar por la validación de este tipo de cosas. ¿Por qué no simplemente verificar que tiene una @ y al menos una? y cumple con una longitud mínima simple. Es trivial ingresar un correo electrónico falso y aun así coincidir con cualquier expresión regular válida. Supongo que los falsos positivos son mejores que los falsos negativos.

Draemon
fuente
1
Sí, pero ¿ qué RFC? :) Este [RFC ‐ 5322 – validador] ( stackoverflow.com/questions/201323/… ) solo tiene alrededor de cuarenta líneas.
tchrist el
14
A . no es requerido. Un TLD puede tener direcciones de correo electrónico, o podría haber una dirección IPv6
Sijmen Mulder
1
Las RFC no son el final de la historia: ICANN ya no permite dominios 'sin punto': icann.org/news/announcement-2013-08-30-en
Synchro
64

Al decidir qué caracteres están permitidos, recuerde a sus amigos apostrofeados y con guiones. No tengo control sobre el hecho de que mi empresa genera mi dirección de correo electrónico utilizando mi nombre del sistema de recursos humanos. Eso incluye el apóstrofe en mi apellido. No puedo decirle cuántas veces me han bloqueado la interacción con un sitio web por el hecho de que mi dirección de correo electrónico es "no válida".

DOK
fuente
44
Este es un problema súper común en los programas que hacen suposiciones injustificadas sobre lo que está y no está permitido en el nombre de una persona. Uno no debería hacer tales suposiciones, solo aceptar cualquier carácter que los RFC relevantes indiquen que uno debe.
tchrist el
44
Si. ¡Estoy particularmente enfurecido contra los programadores que rechazan las letras mayúsculas en las direcciones de correo electrónico! Tonto y / o vago.
PhiLho
63

Esta expresión regular es de la biblioteca Email :: Valid de Perl . Creo que es el más preciso, coincide con los 822. Y se basa en la expresión regular del libro de O'Reilly:

Expresión regular construida utilizando el ejemplo de Jeffrey Friedl en 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
fuente
14
O_O también necesitarías ser un maestro de expresiones regulares para entender lo que está haciendo
Chris McGrath
45

Mientras escribe en PHP, le aconsejo que use la validación integrada de PHP para correos electrónicos.

filter_var($value, FILTER_VALIDATE_EMAIL)

Si está ejecutando una versión php inferior a 5.3.6, tenga en cuenta este problema: https://bugs.php.net/bug.php?id=53091

Si desea obtener más información sobre cómo funciona esta validación integrada , consulte aquí: ¿Funciona realmente filter_var FILTER_VALIDATE_EMAIL de PHP?

SimonSimCity
fuente
obtiene un voto, exactamente lo que iba a decir. No maneja IDN, pero la conversión a código insignificante lo resuelve de antemano. PHP> = 5.3 tiene idn_to_ascii () para esto. Una de las mejores y más fáciles formas de validar un correo electrónico.
Taylor
43

Cal Henderson (Flickr) escribió un artículo llamado Analizar direcciones de correo electrónico en PHP y muestra cómo hacer un análisis de direcciones de correo electrónico que cumpla con RFC (2) 822. También puede obtener el código fuente en php , python y ruby ​​que tiene licencia cc .

adnam
fuente
me dijo que a@bera válido
dsdsdsdsd
1
@dsdsdsdsd Porque a@bes válido ... en este caso bes el dominio de nivel superior.
rink.attendant.6
42

Nunca me molesto en crear con mi propia expresión regular, porque lo más probable es que otra persona ya haya encontrado una versión mejor. Siempre uso regexlib para encontrar uno de mi agrado.

Kon
fuente
1
Esto se marcó por su longitud y contenido, pero sigue siendo una buena contribución con 41 votos y no debe eliminarse.
Será el
37

No hay uno que sea realmente utilizable.
Discuto algunos problemas en mi respuesta a ¿Hay una biblioteca php para la validación de la dirección de correo electrónico? , se discute también en Regexp reconocimiento de dirección de correo electrónico duro?

En resumen, no espere que una expresión regular utilizable haga un trabajo adecuado. Y la mejor expresión regular validará la sintaxis, no la validez de un correo electrónico ([email protected] es correcto pero probablemente rebotará ...).

PhiLho
fuente
Corrígeme si me equivoco, pero creo que PHP usa patrones PCRE. Si es así, deberías poder crear algo similar al patrón RFC 5322 de Abigail .
tchrist el
@tchrist: no estoy seguro si PCRE ha alcanzado esta sintaxis (que descubrí). Si es así, no estoy seguro si el PCRE de PHP ha alcanzado esta versión de PCRE ... Bueno, si entiendo correctamente esta sintaxis, también puede usar un analizador PEG, mucho más claro y completo que una expresión regular de todos modos.
PhiLho
PCRE lo ha alcanzado, pero quizás PHP no lo haya hecho con PCRE. ☹
tchrist
36

Una expresión regular simple que al menos no rechazaría una dirección de correo electrónico válida sería buscar algo, seguido de un signo @ y luego algo seguido de un punto y al menos 2 cosas. No rechazará nada, pero después de revisar las especificaciones no puedo encontrar ningún correo electrónico que sea válido y rechazado.

correo electrónico = ~ /.+@[^@]+\.[^@]{2,}$/

spig
fuente
3
Esto es lo que estaba buscando. No es muy restrictivo, pero se asegura de que solo haya 1 @ (ya que estamos analizando una lista y queremos asegurarnos de que no falten comas). Para su información, puede tener una @ a la izquierda si está entre comillas: Valid_email_addresses , pero es bastante marginal.
Josh
2
Después de usarlo, me di cuenta de que no funcionaba exactamente. /^[^@]+@[^@]+\.[^@]{2}[^@]*$/ en realidad comprueba el signo 1 @. Su expresión regular dejará pasar múltiples debido a. * Al final.
Josh
1
Derecha. No estoy tratando de rechazar todos los inválidos, solo evito rechazar una dirección de correo electrónico válida.
spig
1
Sería mucho mejor usar esto: /^[^@]+@[^@]+\.[^@]{2,4}$/asegurándose de que termine con 2 a 4 caracteres que no sean @. Como señaló @Josh, ahora permite una @ extra al final. Pero también puede cambiar eso a: /^[^@]+@[^@]+\.[^a-z-A-Z]{2,4}$/ya que todos los dominios de nivel superior son caracteres aZ. puede reemplazar 4con 5o más permitiendo que los nombres de dominio de nivel superior sean más largos en el futuro también.
VUELO el
@FLY, ka @ foo. devuelve correcto ¿Se supone que, según los estándares?
SexyBeast
29

Puede usar el empleado por el complemento de validación jQuery:

/^((([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
caos
fuente
Esto parece estar haciendo un buen trabajo. Permitió: a-b'[email protected]pero pudo detectar variaciones inapropiadas, como a-b'[email protected]ya-b'[email protected]
dsdsdsdsd
25

Para obtener la evaluación más completa de la mejor expresión regular para validar una dirección de correo electrónico, consulte este enlace; " Comparación de la dirección de correo electrónico que valida expresiones regulares "

Aquí está la expresión superior actual para fines de referencia:

/^([\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
fuente
spoon16: Ese enlace no es realmente correcto. Su afirmación de que no puede haber un patrón perfecto para validar las direcciones de correo electrónico es evidentemente culpable. Usted puede , pero usted tiene que asegurarse de que siga el RFC derecha pie de la letra. Y también debes elegir el RFC correcto.
tchrist el
El "mejor" en este momento no funciona con Java Regex, incluso después de escapar y convertir correctamente la cadena.
Eric Chen
23

Sin mencionar que los nombres de dominio no latinos (chino, árabe, griego, hebreo, cirílico, etc.) se permitirán en un futuro próximo . Todos tienen que cambiar la expresión regular del correo electrónico utilizada, porque esos caracteres seguramente no serán cubiertos por [a-z]/ini\w . Todos fallarán.

Después de todo, la mejor manera de validar la dirección de correo electrónico es enviar un correo electrónico a la dirección en cuestión para validar la dirección. Si la dirección de correo electrónico es parte de la autenticación del usuario (registro / inicio de sesión / etc.), puede combinarla perfectamente con el sistema de activación del usuario. Es decir, enviar un correo electrónico con un enlace con una clave de activación única a la dirección de correo electrónico especificada y solo permitir el inicio de sesión cuando el usuario haya activado la cuenta recién creada usando el enlace en el correo electrónico.

Si el propósito de la expresión regular es solo informar rápidamente al usuario en la interfaz de usuario que la dirección de correo electrónico especificada no se ve en el formato correcto, lo mejor es verificar si coincide básicamente con la siguiente expresión regular:

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

Simple como eso. ¿Por qué te importarían los caracteres utilizados en el nombre y el dominio? Es responsabilidad del cliente ingresar una dirección de correo electrónico válida, no la del servidor. Incluso cuando el cliente ingresa una dirección de correo electrónico sintácticamente válida como [email protected], esto no garantiza que sea una dirección de correo electrónico legítima. Nadie regex puede cubrir eso.

BalusC
fuente
44
Estoy de acuerdo en que enviar un mensaje de autenticación suele ser la mejor manera para este tipo de cosas, sintácticamente correctas y válidas no son lo mismo. Me siento frustrado cuando tengo que escribir mi dirección de correo electrónico dos veces para "Confirmación" como si no pudiera ver lo que escribí. De todos modos, solo copio el primero al segundo, parece que cada vez se usa más.
PeteT
¡de acuerdo! pero esta expresión regular no creo que sea válida porque permite spacesdespués de @.eg. [email protected] com netse considera un correo electrónico válido mediante el uso de la expresión regular anterior donde, como debería ser, devuelve no válido.
CB4
20

La especificación HTML5 sugiere una expresión regular simple para validar direcciones de correo electrónico:

/^[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])?)*$/

Esto intencionalmente no cumple con RFC 5322 .

Nota: Este requisito es una violación intencional de RFC 5322 , que define una sintaxis para las direcciones de correo electrónico que es simultáneamente demasiado estricta (antes del @carácter), demasiado vaga (después del @carácter) y demasiado laxa (permitiendo comentarios, caracteres de espacios en blanco, y cadenas citadas de maneras desconocidas para la mayoría de los usuarios) para ser de uso práctico aquí.

La longitud total también podría limitarse a 254 caracteres, según la errata RFC 3696 1690 .

Ross Allan
fuente
¡La mejor respuesta! Aquí hay un enlace a la recomendación de w3: w3.org/TR/html5/forms.html#valid-e-mail-address Esta expresión regular es adoptada por muchos navegadores.
Ryan Taylor el
3
Esta no es la mejor respuesta! Este patrón coincide con esta dirección totalmente válido: invalid@emailaddress. ¡Instaría precaución y muchas pruebas antes de usarlo!
Sheridan
@Sheridan, si cree que hay un problema con la especificación HTML5, puede plantear un problema aquí: github.com/w3c/html/issues
Luna
Esto no agrega mucho sobre stackoverflow.com/a/8829363 y en mi humilde opinión sería mejor como una edición o comentario sobre eso.
ejemplo @ localhost es válido, pero para una aplicación del mundo real es posible que desee aplicar una extensión de dominio, todo lo que necesita hacer es cambiar el * final a un + para lograr esto (cambiar esa parte del patrón de 0+ a 1+ )
Mitch Satchwell
15

Para una demostración vívida, el siguiente monstruo es bastante bueno pero todavía no reconoce correctamente todas las direcciones de correo electrónico sintácticamente válidas: reconoce comentarios anidados de hasta cuatro niveles de profundidad.

Este es un trabajo para un analizador sintáctico, pero incluso si una dirección es sintácticamente válida, es posible que aún no se pueda entregar. A veces tienes que recurrir al método hillbilly de "¡Hola, todos, mírennos!"

// 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
fuente
12

De acuerdo con el estándar oficial RFC 2822, la expresión regular de correo electrónico válida es

(?:[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 quieres usarlo en Java es realmente muy fácil

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_
fuente
1
Su expresión regular no incluye la primera letra mayúscula, por ejemplo, [email protected], lo que podría ser molesto para algunos usuarios. Use este en su lugar:(?:[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 Gracias, edite la respuesta, aceptaré el cambio.
AZ_
Si agrego ese cambio a su respuesta, ya no será RFC 2822, así que no sé si eso es correcto.
Kebab Krabby
11

Aquí está el PHP que uso. Elegí esta solución en el espíritu de "los falsos positivos son mejores que los falsos negativos", según lo declarado por otro comentarista aquí Y con respecto a mantener el tiempo de respuesta y la carga del servidor ... realmente no hay necesidad de desperdiciar recursos del servidor con una expresión regular cuando esto eliminará el error de usuario más simple. Siempre puede seguir esto enviando un correo electrónico de prueba si lo desea.

function validateEmail($email) {
  return (bool) stripos($email,'@');
}
Mac
fuente
1
a) El "desperdicio de recursos del servidor" es infinitesimal, pero si está tan inclinado, puede hacerlo del lado del cliente con JS b) ¿Qué necesita para enviar un correo de registro y el usuario me ingresa @ forgotthedotcom? Su "solución" falla y pierde un usuario.
johnjohn el
a) Confiar en una validación JS que fallará cuando JavaScript esté deshabilitado tampoco parece ser la mejor idea (solo por cierto)
auco
11

RFC 5322 estándar:

Permite la parte local del átomo de punto, la parte local de la cadena entre comillas, la parte local obsoleta (átomo de punto mixto y la cadena entre comillas), el dominio de nombre de dominio, (IPv4, IPv6 y la dirección IPv6 asignada a IPv4) dominio literal, y (anidados) 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'

RFC 5321 estándar:

Permite la parte local de átomo de punto, la parte local de cadena de comillas, el dominio de nombre de dominio y el dominio literal de dominio (IPv4, IPv6 y dirección IPv6 asignada a IPv4).

'/^(?!(?>"?(?>\\\[ -~]|[^"])"?){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'

Básico:

Permite la parte local de átomo de punto y el dominio de nombre de dominio (que requiere al menos dos etiquetas de nombre de dominio con el TLD limitado a 2-6 caracteres alfabéticos).

"/^(?!.{255,})(?!.{65,}@)([!#-'*+\/-9=?^-~-]+)(?>\.(?1))*@(?!.*[^.]{64,})(?>[a-z0-9](?>[a-z0-9-]*[a-z0-9])?\.){1,126}[a-z]{2,6}$/iD"
MichaelRushton
fuente
¿En qué idioma del diablo está eso? ¿Veo una /Dbandera y la ha citado con comillas simples pero también ha usado barras para delimitar el patrón? No es Perl, y no puede ser PCRE. ¿Es por lo tanto PHP? Creo que esos son los únicos tres que permiten la recursividad (?1).
tchrist el
Está en PHP, que usa PCRE. Las barras se utilizan solo para delimitar caracteres especiales como paréntesis, corchetes y, por supuesto, barras y comillas simples. El indicador / D, si no lo sabía, es para evitar que se agregue una nueva línea al final de la cadena, que de lo contrario se permitiría.
MichaelRushton
9

Es extraño que "no pueda" permitir TLD de 4 caracteres. Está prohibiendo a las personas de .info y .name , y la limitación de longitud detiene .travel y .museum , pero sí, son menos comunes que los TLD de 2 caracteres y los TLD de 3 caracteres.

También debe permitir alfabetos en mayúsculas. Los sistemas de correo electrónico normalizarán la parte local y la parte de dominio.

Para su expresión regular de la parte de dominio, el nombre de dominio no puede comenzar con '-' y no puede terminar con '-'. Dash solo puede permanecer en el medio.

Si usó la biblioteca PEAR, consulte su función de correo (olvidó el nombre / biblioteca exactos). Puede validar la dirección de correo electrónico llamando a una función, y valida la dirección de correo electrónico de acuerdo con la definición en RFC822.

Joseph Yee
fuente
2
@Joseph Yee: ¿No está RFC 822 un poco anticuado?
tchrist el
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
fuente