104

Pregunta

¿Cómo validar un e-mail que acepte todos los caracteres latinos?

  • Por caracteres latinos me refiero a letras acentuadas, ñ, ç, y todas las usadas por idiomas como español, portugués, italiano... latinos.

Contexto

  • El objetivo es mostrar un icono al lado del texto a medida que el usuario va tipeando su dirección de mail.
  • No me interesa aceptar todos los casos válidos. Fue una decisión de diseño abarcar sólo los mails más frecuentes. Es decir, letras (incluyendo acentos y similares) y los símbolos ._%+-.
  • Puedo usar código de otras fuentes, siempre y cuando sean populares (ej: jQuery).

Código

document.getElementById('email').addEventListener('input', function() {
    campo = event.target;
    valido = document.getElementById('emailOK');
        
    emailRegex = /^[-\w.%+]{1,64}@(?:[A-Z0-9-]{1,63}\.){1,125}[A-Z]{2,63}$/i;
    //Se muestra un texto a modo de ejemplo, luego va a ser un icono
    if (emailRegex.test(campo.value)) {
      valido.innerText = "válido";
    } else {
      valido.innerText = "incorrecto";
    }
});
<p>
    Email:
    <input id="email">
    <span id="emailOK"></span>
</p>

Casos

Estoy usando el regex

/^[-\w.%+]{1,64}@(?:[A-Z0-9-]{1,63}\.){1,125}[A-Z]{2,63}$/i

Que funciona perfecto en casos como

abcde.fghi@gmail.com
nombre-apellido@do-mi-nio.info

Pero falla con acentos y otras letras latinas

germán@bla.com
yo@mi-compañía.com
estação@brasil.com.br
PAGANA
  • 540
  • 4
  • 11
Mariano
  • 23,777
  • 20
  • 70
  • 102
  • 1
    En serio tenes direcciones e-mail con acentos? En tal caso, las clases (grupos entre corchetes) pueden incluir cosas como áéíóúÁÉÍÓÚäëïöüÄËÏÖÜàèìòùÀÈÌÒÙñÑ – Luis Masuelli Dec 01 '15 at 21:03
  • 2
    como [-\w.%+áéíóúÁÉÍÓÚäëïöüÄËÏÖÜàèìòùÀÈÌÒÙñÑ] – Luis Masuelli Dec 01 '15 at 21:04
  • En Javascript no (en otros lenguajes como PHP y Python sí, pero es más jodido) – Luis Masuelli Dec 01 '15 at 21:07
  • ¿Exáctamente a qué hace referencia cuando menciona 'Carácter latino'? – dwarandae Dec 03 '15 at 03:05
  • 1
    Mariano: Te sugiero mencionar que ya es permitido el uso de caracteres internacionales. Por ejemplo, puedes agregar como referencia https://en.wikipedia.org/wiki/International_email. – Rubén Dec 14 '15 at 13:12

6 Answers6

104

Con esta expresión regular puedes validar cualquier dirección de correo elecrónico que contenga caracteres Unicode:

/^(([^<>()[\]\.,;:\s@\"]+(\.[^<>()[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i

Si lo pruebas en una consola de JavaScript:

> emailRegex.test("abcde.fghi@gmail.com");
< true
> emailRegex.test("germán@bla.com");
< true

Fuente


A partir de ahí, y como muy bien has mencionado, una expresión que se ajusta más a tus necesidades sería la siguiente:

/^(?:[^<>()[\].,;:\s@"]+(\.[^<>()[\].,;:\s@"]+)*|"[^\n"]+")@(?:[^<>()[\].,;:\s@"]+\.)+[^<>()[\]\.,;:\s@"]{2,63}$/i
Hewbot
  • 1,457
  • 2
  • 11
  • 16
  • Esa expresión regular la ví en una respuesta del stackoverflow inglés, y objetaban que acepta muchos emails no ICANN como `**@as`, ya que esa expresión regular no controla que el dominio deba tener al menos un punto (un dominio), que el nombre de usuario no sea mayor de 255 carácteres, etc. Este e-mail también parece que se lo tragaría: `juan@{{192.168.1.52}}` – Peregring-lk Nov 25 '16 at 14:49
  • 1
    @Peregring-lk Gracias por agregar los comentarios explicando la diferencia de RFC vs ICANN. Mi pregunta nunca apuntó a validar *todos* los posibles formatos de e-mail (eso es imposible), aclarando que "*fue una decisión de diseño abarcar sólo los mails más frecuentes*". En particular, es una primera validación que cubre un altísimo porcentaje de direcciones. Pero como se argumenta [en la respuesta de Braiam](http://es.stackoverflow.com/a/297/127), sólo se puede verificar enviando un mail. No obstante, este regex [sí valida que haya un punto en el dominio](https://regex101.com/r/3X8Gyk/1). – Mariano Feb 23 '17 at 03:12
34

Existen ciertas restricciones para emails pero puedo comentar que regularmente deben basarse en estas reglas:

  • Mayúsculas y minúsculas del alfabeto ingles.
  • Números de 0 al 9
  • puede contener punto pero no al inicio o repetirse.
  • puede usar los caracteres: !#$%&'*+-/=?^_`{|}~

Existen restricciones con ciertos tipos de email por ejemplo si contienen:

  • Alfabeto griego.
  • Caracteres cirílicos.
  • Caracteres japoneses.
  • Alfabeto latín con diacríticos.

ejemplos no aceptados como direcciones validas de email:

червь.ca®rton@picnic.com

josé.patroñinio@hotdog.com

Ver más :

https://en.wikipedia.org/wiki/Email_address https://www.rfc-editor.org/rfc/rfc5322

Imagino un email con caracteres cirilicos, peor aún si lo que quieres es almacenar esos datos en una BD, que tipo de SQL collation utilizar!

Pero bueno la pregunta se refiere a como validar ese tipo de emails, este es un script que ayudaría con la tarea:

function validarEmail(valor) {
  if (/^(([^<>()[\]\.,;:\s@\"]+(\.[^<>()[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i.test(valor)){
   alert("La dirección de email " + valor + " es correcta!.");
  } else {
   alert("La dirección de email es incorrecta!.");
  }
}

por ejemplo:

validarEmail("jorgésys.boc+al@hotflow.com");

El script te mostraría que la dirección email es correcta.


  • Actualización:

Actualmente ya es posible usar caracteres internacionales en nombres de dominio y direcciones de correo electrónico.

Las direcciones de correo electrónico tradicionales están limitadas a los caracteres del alfabeto inglés y algunos otros caracteres especiales. Las siguientes son direcciones de correo electrónico tradicionales válidas:

  Abc@example.com                                (English, ASCII)
  Abc.123@example.com                            (English, ASCII)
  user+mailbox/department=shipping@example.com   (English, ASCII)
  !#$%&'*+-/=?^_`.{|}~@example.com               (English, ASCII)
  "Abc@def"@example.com                          (English, ASCII)
  "Fred Bloggs"@example.com                      (English, ASCII)
  "Joe.\\Blow"@example.com                       (English, ASCII)

El correo electrónico internacional, por el contrario, utiliza caracteres Unicode codificados como UTF-8, lo que permite codificar el texto de las direcciones en la mayoría de los sistemas de escritura del mundo.

Las siguientes son todas las direcciones de correo electrónico internacionales válidas:

  用户@例子.广告                   (Chinese, Unicode)
  अजय@डाटा.भारत                    (Hindi, Unicode)
  квіточка@пошта.укр             (Ukrainian, Unicode)
  θσερ@εχαμπλε.ψομ               (Greek, Unicode)
  Dörte@Sörensen.example.com     (German, Unicode)
  аджай@экзампл.рус              (Russian, Unicode)
Jorgesys
  • 103,630
  • 13
  • 52
  • 124
  • 2
    Gracias por el dato. Realmente me sirve. Si bien el alcance definido no debe cubrir todo el RFC, sino más bien los casos más genéricos, me interesa evaluarlo como opción: ¿Cómo se implementaría esto en JavaScript? – Mariano Dec 01 '15 at 21:23
  • Es un punto totalmente válido... Creo que si pensás que no debería validarse, debería estar explícito en la respuesta. Este tipo de respuestas bien fundamentadas me sirve para definir el alcance. – Mariano Dec 01 '15 at 21:34
18

He encontrado un artículo aquí (en Inglés) que habla de algunas declaraciones diferentes expresiones regulares que pueden verificar direcciones de correo electrónico basados en el estándar RFC. Hay muchas declaraciones de expresiones regulares recomendada diferentes y no hay un único todo-en-una solución. Pero esta expresión regular es probablemente el que me iría con, añadiendo caracteres acentuados a la lista de caracteres válidos también.

\A[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\z
SnareChops
  • 347
  • 2
  • 9
  • Y ¿Cómo sería una versión que funcione en JavaScript y que acepte acentos y demás caracteres latinos? – Mariano Dec 01 '15 at 21:36
  • El problema es que un email RFC-válido podría ser ICANN-inválido. Es decir, que RFC lo permita pero no haya ningún proveedor que te permita tener emails con esas direcciones. – Peregring-lk Nov 25 '16 at 14:50
15

¿Cómo validar un email que acepte todos los caracteres latinos?

La única forma 100% segura de verificar si un email es valido es enviando uno. Si el usuario escribio el correo mal, ellos simplemente reintentaran.

Según RFC 5322, presidencia@gobierno.pais es un email "valido", pero, ¿alguien lo va a recibir? ¿Existe un servidor detras del dominio que acepte correos? Esas son las preocupaciones que deberias tener. Lo que seas que estas haciendo, una lista de distribución, registro, etc. debe de enviar un correo de confirmación para validarlo. La implementacion dependera del stack que uses (C#, PHP, Java?) y hací tendrás correos validos que alguien recibe.

Puedes implementar algo en el lado del cliente que al menos diga "este es una direción de correo electronico", pero no debería de ser tu herramienta de "validación", solo trata de que el usuario se de cuenta de que lo que escribió es #($^%#$@^(#$^.com. Si el cliente utiliza un navegador moderno, puedes utilizar <input type="email"> en tu formulario, esto eliminará la necesidad de mantener el regex.

Braiam
  • 255
  • 1
  • 15
  • 1
    Totalmente de acuerdo, la única forma de validar es desde el server. Y sí, la idea es que sea una primera etapa de validación genérica, pero sin depender sólo en esto (al fin y al cabo JavaScript podría estar deshabilitado). Muy correcta tu visión, y es la forma en que lo quiero implementar. – Mariano Dec 03 '15 at 03:51
14

Simplemente señalar que, de acuerdo a la especificación oficial, el regex que representa una dirección de email ortográficamente válida es el siguiente:

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

Puse a propósito el término dirección de email ortográficamente válida, porque lo que define una dirección de email realmente válida es que ésta funcione, es decir, que exista y pueda recibir emails.

De ahí se desprende que una verificación por medio de Javascript no es suficiente. Puede ayudarnos a hacer una validación [ortográfica], a condición de que Javascript esté activado del lado del cliente.

Si se quiere verificar que el email realmente existe, no hay otra manera que enviando un email y que el destinatario responda. Es a eso a lo que se le puede llamar con toda propiedad validación [real] de un email.

De hecho, eso es lo que hacen todos los servicios de suscripción serios, nos envían un email que debemos verificar para quedar inscritos definitivamente en sus sitios o en sus listas de distribución.

Me permito mostrar gráficamente los pasos para validar un e-mail. Veremos que lo tratado aquí es apenas la etapa 2/5 de un proceso de validación que comprendería 5 etapas:

  • Etapa 1: El usuario escribe un e-mail
  • Etapa 2: Validación ortográfica del e-mail escrito por el usuario
  • Etapa 3: Verificar si el dominio correspondiente al e-mail validado ortográficamente posee un servidor de e-mail
  • Etapa 4: Enviar una petición (ping) o un email para verificar que el servidor está aceptando e-mails
  • Etapa 5: El e-mail fue recibido correctamente en esa dirección

Hasta que no llegamos a la etapa 5, no podemos decir que el e-mail ha sido validado.

introducir la descripción de la imagen aquí

Si todos modos el OP solicita un método de validación que acepte direcciones con ñ y otros caracteres no definidos hasta el momento por la especificación oficial de w3.org (enlace de más arriba), el regex mencionado en una anterior respuesta funciona.

El código que sigue es el mismo usado en la pregunta, pero implementando por un lado el regex oficial y el regex que permite caracteres latinos tales como la ñ.

document.getElementById('email').addEventListener('input', function() {
    campo = event.target;
    valido = document.getElementById('emailOK');
        
  var reg = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;

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

    //Se muestra un texto a modo de ejemplo, luego va a ser un icono
    if (reg.test(campo.value) && regOficial.test(campo.value)) {
      valido.innerText = "válido oficial y extraoficialmente";
    } else if (reg.test(campo.value)) {
      valido.innerText = "válido extraoficialmente";

    } else {
      valido.innerText = "incorrecto";

}
});
<p>
    Email:
    <input id="email">
    <span id="emailOK"></span>
</p>

Validación [ortográfica] en HTML5

HTML5 permite declarar nuestro `input`del tipo email y se encarga (en parte) de la validación por nosotros, [como dice MDN][3]:

email: El atributo representa una dirección de correo electrónico. Los saltos de línea se eliminan automáticamente del valor ingresado. Puede ingresarse una dirección de correo no válida, pero el campo de ingreso sólo funcionará si la dirección satisface la producción ABNF 1*( atext / "." ) "@" ldh-str 1*( "." ldh-str ) donde atext está definida en RFC 5322, sección 3.2.3 y ldh-str está definida en RFC 1034, sección 3.5.

Se puede combinar email con el atributo pattern:

pattern : Una expresión regular contra la que el valor es evaluado. El patrón debe coincidir con el valor completo, no solo una parte. Se puede usar el atributo title para describir el patrón como ayuda al usuario. Este atributo aplica cuando el atributo type es text, search, tel, url, email, o password, y en caso contrario es ignorado. El lenguaje de expresión regular es el mismo que el algoritmo RegExp de JavaScript, con el parámetro 'u' que permite tratar al patrón como una secuencia de código Unicode. El patrón no va rodeado por diagonales.

La desventaja es que no todos los clientes son compatibles con HTML5.

<form>
<input type="email" pattern='^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$' title="Entre un email válido"  placeholder="Entre su email">
<input type="submit" value="Submit">
</form>
A. Cedano
  • 86,578
  • 19
  • 122
  • 221
  • Aparentemente omitiste la **Etapa 6** que es cuando el usuario hace *click* en un enlace específico y el servidor recibe la confirmación. Además este paso favorece la posibilidad de que el usuario vea realmente el mensaje (lo busque de ser necesario) y mejora la calificación NO-ES-SPAM de futuros mails que se envíen desde el mismo servidor/dominio. – lalengua May 25 '18 at 02:16
11

Según la RFC 6531 se tendrían que soportar más caracteres de a los que estamos acostumbrados. Pero los servidores lo limitan con otras anteriores. No veo una solución con un rango único que implique introducir «todos los caracteres latinos». A pesar de que parece que van juntos (como en esta tabla del 0080 al 00FF), hay otros por en medio.

Una posible regex para los caracteres latinos que podrían interesarte (fuente) y añadiendo la (sugerencia):

/[A-Za-z\u0021-\u007F\u00C0-\u00D6\u00D8-\u00f6\u00f8-\u00ff]+/g

Se podría juntar con tu regex, las que ya han indicado anteriormente o una según la RFC 2822, como esta, para que no excluya los rangos que te interesan (que hay muchos tipos de tildes) (fuente):

^([^\x00-\x20\x22\x28\x29\x2c\x2e\x3a-\x3c\x3e\x40\x5b-\x5d\x7f-\xff]+|\x22([^\x0d\x22\x5c\x80-\xff]|\x5c[\x00-\x7f])*\x22)(\x2e([^\x00-\x20\x22\x28\x29\x2c\x2e\x3a-\x3c\x3e\x40\x5b-\x5d\x7f-\xff]+|\x22([^\x0d\x22\x5c\x80-\xff]|\x5c[\x00-\x7f])*\x22))*\x40([^\x00-\x20\x22\x28\x29\x2c\x2e\x3a-\x3c\x3e\x40\x5b-\x5d\x7f-\xff]+|\x5b([^\x0d\x5b-\x5d\x80-\xff]|\x5c[\x00-\x7f])*\x5d)(\x2e([^\x00-\x20\x22\x28\x29\x2c\x2e\x3a-\x3c\x3e\x40\x5b-\x5d\x7f-\xff]+|\x5b([^\x0d\x5b-\x5d\x80-\xff]|\x5c[\x00-\x7f])*\x5d))*$
dayer
  • 111
  • 4
  • 1
    Buena respuesta. Sin duda sería ideal ajustarse a la RFC6531. Sin embargo, creo que no sería nada fácil implementarlo... En cuanto al primer regex, está dejando afuera varios caracteres del rango [\u0021-\u007F](https://en.wikipedia.org/wiki/Basic_Latin_(Unicode_block)) (por ejemplo los símbolos `_%+-`)... En cuanto al segundo, deja afuera a los caracteres acentuados (como `á = \u00E1 = \xc3\xa1`). – Mariano Dec 02 '15 at 06:15
  • 1
    Estupendo. La primera regex que puse era para caracteres latinos, no los símbolos `_%+-` (la he editado para añadirlos). Respecto a la segunda ya advertí de que es según la RFC 2822, que se podía tomar de base para añadirle la primera o las de respuestas previas. – dayer Dec 02 '15 at 09:11