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

Resuelto acrosman asked hace 16 años • 75 respuestas

A lo largo de los años, poco a poco he desarrollado una expresión regular que valida la mayoría de las direcciones de correo electrónico correctamente, asumiendo que no utilizan 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 permitía TLD de cuatro caracteres ).

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

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

acrosman avatar Oct 14 '08 21:10 acrosman
Aceptado

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 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 su 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 bytes sin firmar en un dirección delimitada por puntos, lo cual es ilegal. El resto parece ser consistente con la gramática RFC 5322 y pasa varias pruebas usando grep -Po, incluidos casos de nombres de dominio, direcciones IP, malas y nombres de cuentas con y sin comillas.

Al corregir el 00error en el patrón IP, obtenemos una expresión regular que funciona y es bastante rápida. (Elimine la versión renderizada, no la rebaja, para obtener 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 claro 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 utilizada, por ejemplo, en PHP) pueden analizar correctamente RFC 5322 sin problemas . Python y C# también pueden hacer eso, pero usan una sintaxis diferente a la de los dos primeros. Sin embargo, si se ve obligado a utilizar uno de los muchos lenguajes de coincidencia de patrones menos potentes, lo mejor es utilizar un analizador real.

También es importante comprender que validarla según el RFC no indica absolutamente nada sobre si esa dirección realmente existe en el dominio proporcionado o si la persona que ingresa la dirección es su verdadero propietario. La gente inscribe a otros en listas de correo de esta manera todo el tiempo. Arreglar eso requiere un tipo de validación más sofisticado que implica enviar a esa dirección un mensaje que incluye un token de confirmación que debe ingresarse en la misma página web donde estaba la dirección.

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

Para PHP, no debe utilizar el patrón indicado en Validar una dirección de correo electrónico con PHP, la forma correcta que 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 demás patrones que no son RFC. Ni siquiera es lo suficientemente inteligente como para manejar RFC 822 , y mucho menos RFC 5322. Éste , sin embargo, lo es.

Si quiere ser sofisticado y pedante, implemente un motor de estado completo . Una expresión regular sólo 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 manejarla es simplemente 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 según cada RFC. Esto permite una experiencia potencialmente más placentera, como

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

Consulte también Validación de direcciones de correo electrónico , incluidos los comentarios. O comparar direcciones de correo electrónico validando expresiones regulares .

Visualización de expresiones regulares

Demostración de depuración

bortzmeyer avatar Oct 14 '2008 14:10 bortzmeyer

No debes utilizar expresiones regulares para validar direcciones de correo electrónico.

En su lugar, en C# 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 en total conformidad con RFC822.

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

En algunos de estos casos, sólo la última parte de las cadenas se analiza como dirección; el resto antes de eso es el nombre para mostrar. Para obtener una dirección de correo electrónico simple sin ningún nombre para mostrar, puede comparar 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
}

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

Si realmente quieres usar una expresión regular, aquí la tienes :

(?:(?:\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 avatar Dec 14 '2009 20:12 SLaks

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

  • No detectará errores tipográficos comunes.
  • No impide 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. En muchos casos, tendrás que enviar un correo de confirmación de todos modos por razones de seguridad o éticas (por lo que no puedes, por ejemplo, registrar a alguien en un servicio en contra de su voluntad).

JacquesB avatar Oct 14 '2008 19:10 JacquesB

Todo depende de qué tan preciso quieras ser. Para mis propósitos, donde solo intento evitar cosas como bob @ aol.com(espacios en correos electrónicos) o steve(ningún dominio) o mary@aolcom(sin punto antes de .com), uso

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

Claro, coincidirá con cosas que no son direcciones de correo electrónico válidas, pero es cuestión de obtener errores simples y comunes.

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

Andy Lester avatar Oct 14 '2008 14:10 Andy Lester