Cómo validar un email en JavaScript: desde regex simple hasta un análisis completo bajo el capó
\n\nCada desarrollador se ha enfrentado al menos una vez en la vida a la pregunta: «How can I validate an email address in JavaScript?». Esta pregunta en Stack Overflow ha acumulado miles de visitas y cientos de respuestas, porque el tema es una verdadera madeja de matices. Hoy no solo daremos código listo, sino que miraremos bajo el capó: analizaremos por qué una verificación simple puede dejar pasar a@b o bloquear "test@[IPv6:2001:db8::1]". ¡Allá vamos!
¿Por qué «solo un regex» es una mala idea?
\n\nLa solución más popular en internet es copiar una expresión regular. Pero seamos honestos: las direcciones de email son un caos. La especificación RFC 5321 y RFC 5322 permite usar caracteres como +, -, ., % e incluso comentarios entre paréntesis. Además, existen dominios como museum o @[192.168.1.1]. Intenta meter todo eso en una sola línea de regex y terminarás dejando pasar una dirección válida o bloqueando a un usuario real.
Aquí hay un ejemplo que se encuentra a menudo en Stack Overflow:
\n\nconst emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n\nEste código funciona para el 90% de los casos, pero:
\n- \n
- Deja pasar
test@localhost(válido para una red local) \n - Bloquea
"test@[192.168.1.1]"(válido según RFC) \n - No verifica la longitud del dominio ni la presencia de puntos \n
Moraleja: no intentes escribir un regex perfecto. Es mejor usar una combinación de una verificación simple + validación del lado del servidor.
\n\nAnatomía de una dirección de email: qué saber antes de escribir código
\n\nAntes de escribir un validador, analicemos la estructura de un email según la especificación:
\n\n- \n
- Parte local (antes de @): puede contener letras, números, puntos, signos más, guiones, pero no puede comenzar ni terminar con un punto. Se permiten comillas para caracteres especiales. \n
- Dominio (después de @): consiste en etiquetas separadas por puntos. Cada etiqueta tiene de 1 a 63 caracteres. El dominio puede ser una dirección IP entre corchetes. \n
- Longitud total: no más de 254 caracteres. \n
Sabiendo esto, podemos escribir una verificación más significativa.
\n\nPaso 1: Validación simple pero funcional (para el 99% de los casos)
\n\nEmpecemos con el código que se usa en proyectos reales (por ejemplo, en Angular o React). No es perfecto, pero es suficiente para la mayoría de los formularios:
\n\nfunction isEmailSimple(email) {\n // Eliminamos espacios\n const trimmed = email.trim();\n \n // Verificación de cadena vacía\n if (!trimmed) return false;\n \n // Estructura básica: algo @ algo . algo\n const atIndex = trimmed.lastIndexOf('@');\n if (atIndex < 1 || atIndex === trimmed.length - 1) return false;\n \n const localPart = trimmed.slice(0, atIndex);\n const domain = trimmed.slice(atIndex + 1);\n \n // El dominio debe contener al menos un punto\n const dotIndex = domain.lastIndexOf('.');\n if (dotIndex < 1 || dotIndex === domain.length - 1) return false;\n \n // Verificación de longitud\n if (trimmed.length > 254) return false;\n if (localPart.length > 64) return false;\n \n return true;\n}\n\n// Ejemplos:\nconsole.log(isEmailSimple('user@example.com')); // true\nconsole.log(isEmailSimple('a@b.c')); // true (formalmente válido)\nconsole.log(isEmailSimple('user@localhost')); // false (sin punto)\nconsole.log(isEmailSimple('@example.com')); // false\n\n\nEste código ya es mejor que un regex ciego. Verifica la estructura, la longitud y la presencia de @ con un punto. Pero deja pasar user@[192.168.1.1] — para la mayoría de los formularios web, esto no es crítico.
Paso 2: Validación avanzada considerando RFC (casi como en el navegador)
\n\nLos navegadores modernos utilizan validación incorporada a través del atributo type="e