La expresión regular de la que recibo más comentarios, por no hablar de los informes de «errores», es la que encontrarás justo en la página de inicio de este sitio: \b+@+\\b. Esta expresión regular, afirmo, coincide con cualquier dirección de correo electrónico. La mayoría de los comentarios que recibo refutan esta afirmación mostrando una dirección de correo electrónico que no coincide con esta expresión regular. Normalmente, el informe de «error» también incluye una sugerencia para hacer que la expresión regular sea «perfecta».
Como explico a continuación, mi afirmación sólo es válida si se acepta mi definición de lo que es una dirección de correo electrónico válida y lo que no lo es. Si quieres usar una definición diferente, tendrás que adaptar la regex. La coincidencia de una dirección de correo electrónico válida es un ejemplo perfecto que muestra que (1) antes de escribir una expresión regular, usted tiene que saber exactamente lo que está tratando de coincidir, y lo que no; y (2) a menudo hay un compromiso entre lo que es exacto, y lo que es práctico.
La virtud de mi expresión regular anterior es que coincide con el 99% de las direcciones de correo electrónico en uso hoy en día. Todas las direcciones de correo electrónico que coincide puede ser manejado por el 99% de todo el software de correo electrónico por ahí. Si buscas una solución rápida, sólo tienes que leer el siguiente párrafo. Si quiere conocer todas las ventajas y desventajas y obtener un montón de alternativas para elegir, siga leyendo.
Si quiere utilizar la expresión regular anterior, hay dos cosas que debe entender. En primer lugar, las expresiones regulares largas dificultan el formateo agradable de los párrafos. Así que no incluí a-z en ninguna de las tres clases de caracteres. Esta regex está pensada para ser utilizada con la opción «case insensitive» de su motor regex activada. En segundo lugar, la expresión regular anterior está delimitada por palabras, lo que la hace adecuada para extraer direcciones de correo electrónico de archivos o bloques de texto más grandes. Si desea comprobar si el usuario ha introducido una dirección de correo electrónico válida, sustituya los límites de las palabras por anclas de inicio y fin de cadena, como las siguientes ^+@+.{2,}$.
El párrafo anterior también se aplica a todos los ejemplos siguientes. Es posible que tengas que cambiar los límites de las palabras por anclas de inicio/final de cadena, o viceversa. Y tiene que activar la opción de coincidencia sin distinción de mayúsculas y minúsculas.
Cambios en la validación de direcciones de correo electrónico
Antes de que la ICANN hiciera posible que cualquier empresa bien financiada creara sus propios dominios de primer nivel, los dominios de primer nivel más largos eran los raramente utilizados .museum y .travel que tienen 6 letras. Los dominios de primer nivel más comunes eran de 2 letras para los dominios específicos de un país, y de 3 o 4 letras para los dominios de uso general como .com e .info. Muchos regex para validar direcciones de correo electrónico que encontrarás en varios tutoriales y referencias regex siguen asumiendo que el dominio de primer nivel es bastante corto. Las ediciones más antiguas de este tutorial regex mencionaban \b+@+\.{2,4}\b como regex para las direcciones de correo electrónico en su introducción. Sólo hay una pequeña diferencia entre este regex y el de la parte superior de esta página. El 4 al final de la regex restringe el dominio de nivel superior a 4 caracteres. Si utiliza esta regex con anclas para validar la dirección de correo electrónico introducida en su formulario de pedido, [email protected] tiene que hacer sus compras en otra parte. Sí, el TLD .solutions existe y, cuando escribo esto, disaproved.solutions puede ser suyo por 16,88 dólares al año.
Si quiere ser más estricto que {2,} para el dominio de nivel superior, ^+@+\\N2,63}$ es lo más lejos que puede llegar prácticamente. Cada parte de un nombre de dominio no puede tener más de 63 caracteres. No hay dominios de primer nivel de un solo dígito y ninguno contiene cifras. Tampoco parece que la ICANN vaya a aprobar este tipo de dominios.
Las direcciones de correo electrónico pueden estar en servidores de un subdominio como en [email protected]. Todos los regexes anteriores coinciden con esta dirección de correo electrónico, porque he incluido un punto en la clase de caracteres después del símbolo @. Pero los regexes anteriores también coinciden con john@aol…com, que no es válido debido a los puntos consecutivos. Puede excluir estas coincidencias sustituyendo +\. por (?:+\.)+ en cualquiera de las expresiones regulares anteriores. He eliminado el punto de la clase de caracteres y en su lugar he repetido la clase de caracteres y el siguiente punto literal. Por ejemplo, ^+@(?:+\.)+{2,}$ coincide con [email protected] pero no con john@aol…com.
Si quiere evitar que su sistema se ahogue con entradas arbitrariamente grandes, puede sustituir los cuantificadores infinitos por otros finitos. ^{1,64}@(?:{1,63}\N){1,125}{2,63}$ tiene en cuenta que la parte local (antes de la @) está limitada a 64 caracteres y que cada parte del nombre de dominio está limitada a 63 caracteres. No hay un límite directo en el número de subdominios. Pero la longitud máxima de una dirección de correo electrónico que puede ser manejada por SMTP es de 254 caracteres. Así que con una parte local de un solo carácter, un dominio de nivel superior de dos letras y subdominios de un solo carácter, 125 es el número máximo de subdominios.
La regex anterior no limita realmente las direcciones de correo electrónico a 254 caracteres. Si cada parte tiene su longitud máxima, la regex puede coincidir con cadenas de hasta 8129 caracteres de longitud. Se puede reducir el número de subdominios permitidos de 125 a algo más realista como 8. Nunca he visto una dirección de correo electrónico con más de 4 subdominios. Si quiere imponer el límite de 254 caracteres, la mejor solución es comprobar la longitud de la cadena de entrada antes de utilizar una expresión regular. Aunque esto requiere algunas líneas de código de procedimiento, la comprobación de la longitud de una cadena es casi instantánea. Si sólo puede utilizar regexes, puede utilizar ^{6,254}$ como primera pasada para asegurarse de que la cadena no contiene caracteres no válidos y no es demasiado corta o demasiado larga. Si necesita hacer todo con una regex, necesitará una regex que soporte lookahead. La expresión regular ^(?={6,254}$){1,64}@(?:{1,63}\.){1,8}{2,63}$ utiliza un lookahead para comprobar primero que la cadena no contiene caracteres no válidos y no es demasiado corta o demasiado larga. Cuando el lookahead tiene éxito, el resto de la regex hace una segunda pasada sobre la cadena para comprobar la colocación correcta del signo @ y los puntos.
Todas estas regexes permiten los caracteres ._%+- en cualquier lugar de la parte local. Puede forzar que la parte local comience con una letra utilizando ^{0,63} en lugar de ^{1,64} para la parte local: ^{0,63}@(?:{1,63}\.){1,125}{2,63}$. Cuando se utiliza el lookahead para comprobar la longitud total de la dirección, se puede comprobar el primer carácter en el lookahead. No necesitamos repetir la comprobación del carácter inicial al comprobar la longitud de la parte local. Esta regex es demasiado larga para el ancho de la página, así que activemos el modo de espaciado libre:
^(?={5,253}$)
{1,64}@(?:{1,63}\.){1,8}{2,63}$
Los nombres de dominio pueden contener guiones. Pero no pueden comenzar ni terminar con un guión. (?:{0,62})? coincide con un nombre de dominio de entre 1 y 63 caracteres que comienza y termina con una letra o un dígito. El grupo de no captura hace que el medio del dominio y la letra o el dígito final sean opcionales en su conjunto para garantizar que permitimos dominios de un solo carácter y, al mismo tiempo, aseguramos que los dominios con dos o más caracteres no terminen con un guión. La regex general empieza a complicarse bastante:
^{0,63}@
(?:(?:{0,62})?\N1,8}{2,63}$
Los nombres de dominio no pueden contener guiones consecutivos. +(?:-+)* coincide con un nombre de dominio que comienza y termina con una letra o un dígito y que contiene cualquier número de guiones no consecutivos. Esta es la forma más eficaz. Este regex no realiza ningún tipo de retroceso para que coincida con un nombre de dominio válido. Coincide con todas las letras y dígitos al principio del nombre de dominio. Si no hay guiones, el grupo opcional que sigue falla inmediatamente. Si hay guiones, el grupo coincide con cada guión seguido de todas las letras y dígitos hasta el siguiente guión o el final del nombre de dominio. No podemos imponer la longitud máxima cuando los guiones deben ir emparejados con una letra o un dígito, pero las letras y los dígitos pueden ir solos. Sin embargo, podemos utilizar la técnica de búsqueda que utilizamos para imponer la longitud total de la dirección de correo electrónico para imponer la longitud del nombre de dominio y no permitir guiones consecutivos: (?={1,63}\.)+(?:-+)*. Tenga en cuenta que el lookahead también comprueba el punto que debe aparecer después del nombre de dominio cuando se califica completamente en una dirección de correo electrónico. Esto es importante. Si no se comprueba el punto, el lookahead aceptaría nombres de dominio más largos. Dado que el lookahead no consume el texto con el que coincide, el punto no se incluye en la coincidencia global de esta regex. Cuando pongamos esta regex en la regex general para las direcciones de correo electrónico, el punto se emparejará como en las regexes anteriores:
^{0,63}@
(?:(?={1,63}\)+(?:-+)*\.){1,8}{2,63}$
Si incluimos el lookahead para comprobar la longitud total, nuestra regex hace dos pasadas sobre la parte local, y tres pasadas sobre los nombres de dominio para validar todo:
(?={5,253}$){1,64}@
(?:(?={1,63}\.)+(?:-+)*\.){1,8}{2,63}$
En un PC o servidor moderno este regex funcionará perfectamente al validar una única dirección de correo electrónico de 254 caracteres. Rechazar una entrada más larga sería incluso más rápido porque la regex fallará cuando el lookahead falle durante la primera pasada. Pero no recomendaría usar una regex tan compleja como ésta para buscar direcciones de correo electrónico en un gran archivo de documentos o correspondencia. Es mejor que utilices la simple regex de la parte superior de esta página para reunir rápidamente todo lo que se parezca a una dirección de correo electrónico. Deduzca los resultados y luego utilice una regex más estricta si desea filtrar aún más las direcciones no válidas.
Y hablando de retroceso, ninguna de las regex de esta página hace ningún retroceso para coincidir con las direcciones de correo electrónico válidas. Pero particularmente los últimos pueden hacer un poco de backtracking en algo que no es del todo una dirección de correo electrónico válida. Si su regex soporta cuantificadores posesivos, puede eliminar todo el backtracking haciendo que todos los cuantificadores sean posesivos. Dado que no es necesario hacer un backtracking para encontrar coincidencias, hacer esto no cambia lo que coincide con estas expresiones regulares. Sólo permite que fallen más rápido cuando la entrada no es una dirección de correo electrónico válida. Nuestra regex más sencilla se convierte entonces en ^++@++\\N2,}+$ con un + extra después de cada cuantificador. Podemos hacer lo mismo con nuestro regex más complejo:
^(?={5,253}+$){1,64}+@
(?:(?={1,63}+\.)++(?:-++)*+\.){1,8}+{2,63}+$
Una importante contrapartida en todos estos regex es que sólo permiten letras inglesas, dígitos y los símbolos especiales más utilizados. La razón principal es que no confío en que todo mi software de correo electrónico sea capaz de manejar mucho más. Aunque John.O’[email protected] es una dirección de correo electrónico sintácticamente válida, existe el riesgo de que algunos programas interpreten erróneamente el apóstrofe como una comilla de delimitación. Insertar a ciegas esta dirección de correo electrónico en una consulta SQL, por ejemplo, hará que, en el mejor de los casos, falle cuando las cadenas estén delimitadas con comillas simples y, en el peor, abrirá su sitio a ataques de inyección SQL.
Y, por supuesto, hace ya muchos años que los nombres de dominio pueden incluir caracteres no ingleses. Pero la mayoría del software sigue ciñéndose a los 37 caracteres a los que están acostumbrados los programadores occidentales. El apoyo a los dominios internacionalizados abre toda una lata de gusanos de cómo los caracteres no ASCII deben ser codificados. Así que si usas alguna de las expresiones regulares de esta página, cualquiera que tenga una dirección @ทีเอชนิค.ไทย no tendrá suerte. Pero quizás sea revelador que http://ทีเอชนิค.ไทย simplemente redirija a http://thnic.co.th aunque se dediquen a vender dominios .ไทย.
La conclusión es que para decidir qué expresión regular utilizar, tanto si se trata de coincidir con una dirección de correo electrónico como con otra cosa vagamente definida, hay que empezar por considerar todas las compensaciones. ¿Qué tan malo es coincidir con algo que no es válido? ¿Qué tan malo es no coincidir con algo que es válido? ¿Qué complejidad puede tener la expresión regular? ¿Cómo de caro sería tener que cambiar la expresión regular más tarde porque resulta ser demasiado amplia o demasiado estrecha? Las diferentes respuestas a estas preguntas requerirán una expresión regular diferente como solución. Mi expresión regular de correo electrónico hace lo que yo quiero, pero puede que no haga lo que usted quiere.
Las expresiones regulares no envían correo electrónico
No se exceda al intentar eliminar las direcciones de correo electrónico no válidas con su expresión regular. La razón es que usted no sabe realmente si una dirección es válida hasta que intenta enviar un correo electrónico a ella. E incluso eso podría no ser suficiente. Incluso si el correo electrónico llega a un buzón, eso no significa que alguien siga leyendo ese buzón. Si realmente necesitas estar seguro de que una dirección de correo electrónico es válida, tendrás que enviarle un correo electrónico que contenga un código o enlace para que el destinatario realice un segundo paso de autenticación. Y si está haciendo eso, entonces no tiene mucho sentido usar una regex que pueda rechazar direcciones de correo electrónico válidas.
El mismo principio se aplica en muchas situaciones. Cuando se trata de coincidir con una fecha válida, a menudo es más fácil utilizar un poco de aritmética para comprobar los años bisiestos, en lugar de tratar de hacerlo en una expresión regular. Utilice una expresión regular para encontrar posibles coincidencias o compruebe si la entrada utiliza la sintaxis adecuada, y realice la validación real en las posibles coincidencias devueltas por la expresión regular. Las expresiones regulares son una herramienta poderosa, pero están lejos de ser una panacea.
El estándar oficial: RFC 5322
Tal vez se pregunte por qué no hay una expresión regular «oficial» a prueba de errores para hacer coincidir las direcciones de correo electrónico. Bueno, hay una definición oficial, pero no es a prueba de tontos.
El estándar oficial se conoce como RFC 5322. Describe la sintaxis que deben seguir las direcciones de correo electrónico válidas. Se puede (pero no se debe – siga leyendo) implementarla con la siguiente expresión regular. El RFC 5322 deja la parte del nombre de dominio abierta a opciones específicas de implementación que no funcionarán en la Internet actual. La expresión regular implementa la sintaxis «preferida» del RFC 1035, que es una de las recomendaciones del RFC 5322:
A(?:+(?:\)*
| «(?:
| \\)*»)
@ (?:(?:(?:*)?\\N)+(?:*)?
| \|2|?)\N){3}
(?:25|2|??|*:
(?:
| \)+)
])\z
Este regex tiene dos partes: la parte antes de la @, y la parte después de la @. Hay dos alternativas para la parte antes de la @. La primera alternativa permite que conste de una serie de letras, dígitos y ciertos símbolos, incluyendo uno o más puntos. Sin embargo, los puntos no pueden aparecer de forma consecutiva ni al principio o al final de la dirección de correo electrónico. La otra alternativa requiere que la parte que precede a la @ vaya entre comillas dobles, permitiendo cualquier cadena de caracteres ASCII entre las comillas. Los espacios en blanco, las comillas dobles y las barras invertidas deben escaparse con barras invertidas.
La parte que sigue a la @ también tiene dos alternativas. Puede ser un nombre de dominio completamente calificado (por ejemplo, regular-expressions.info), o puede ser una dirección de Internet literal entre corchetes. La dirección literal de Internet puede ser una dirección IP o una dirección de enrutamiento específica del dominio.
La razón por la que no debería utilizar esta expresión regular es que es demasiado amplia. Es posible que su aplicación no pueda manejar todas las direcciones de correo electrónico que permite esta expresión regular. Las direcciones de enrutamiento específicas del dominio pueden contener caracteres de control ASCII no imprimibles, lo que puede causar problemas si su aplicación necesita mostrar las direcciones. No todas las aplicaciones admiten la sintaxis de la parte local con comillas dobles o corchetes. De hecho, el propio RFC 5322 marca como obsoleta la notación que utiliza corchetes.
Obtenemos una implementación más práctica del RFC 5322 si omitimos las direcciones IP, las direcciones específicas de dominio, la sintaxis que utiliza las comillas dobles y los corchetes. Seguirá coincidiendo con el 99,99% de todas las direcciones de correo electrónico que se utilizan hoy en día.
A+(?:\.+)*@
(?:(?:*)?\a)+(?:*)?\a
Ninguno de estos regexes impone límites de longitud en la dirección de correo electrónico global o en la parte local o en los nombres de dominio. El RFC 5322 no especifica ninguna limitación de longitud. Éstas se derivan de las limitaciones de otros protocolos, como el protocolo SMTP para el envío real de correo electrónico. El RFC 1035 sí establece que los dominios deben tener 63 caracteres o menos, pero no lo incluye en su especificación sintáctica. La razón es que un verdadero lenguaje regular no puede imponer un límite de longitud y no permitir guiones consecutivos al mismo tiempo. Pero los sabores modernos de regex no son verdaderamente regulares, así que podemos añadir comprobaciones de límite de longitud usando lookahead como hicimos antes:
A(?={6,254}\z)
(?={1,64}@)
+(?:\)+
@ (?:(?={1,63}\z)(?:*)?\z)+
(?={1,63}\z)(?:*)?\z
Así que incluso cuando se siguen los estándares oficiales, todavía hay que hacer concesiones. No copie ciegamente las expresiones regulares de las bibliotecas en línea o de los foros de discusión. Pruébelas siempre en sus propios datos y con sus propias aplicaciones.
Haga una donación
¿Este sitio web acaba de ahorrarle un viaje a la librería? Por favor, haga una donación para apoyar este sitio, y obtendrá un acceso libre de publicidad de por vida a este sitio!