Regex para validar emails

Primero, la respuesta corta; después, el contexto sincero: el patrón de abajo detecta errores al escribir y el correo de confirmación se ocupa de todo lo demás. Es la combinación que se usa de verdad en producción.

🎙️ Publicado y grabado:

🎧 Escuchar esta guía

El patrón

^[\w.+-]+@[\w-]+\.[\w.-]+$

# léelo así: uno o más de [letras/dígitos/_/./+/-]  @
# bloque del dominio  .  resto del dominio (se permiten puntos)
# anclado con ^...$ porque la validación debe cubrir TODA la cadena

Para copiar y pegar: Python y JavaScript

# Python
import re
EMAIL_RE = re.compile(r"^[\w.+-]+@[\w-]+\.[\w.-]+$")
def looks_like_email(s):
    return bool(EMAIL_RE.match(s.strip()))

// JavaScript
const EMAIL_RE = /^[\w.+-]+@[\w-]+\.[\w.-]+$/;
const looksLikeEmail = s => EMAIL_RE.test(s.trim());

Casos que el patrón debe aceptar y rechazar

✓ debe coincidir:
[email protected]
[email protected]   ← el + importa (lo explicamos abajo)
[email protected]

✗ NO debe coincidir:
ada@example        (sin TLD)
@example.com       (sin parte local)
ada @example.com   (espacio)
ada@@example.com
"ada"@example..com
No rechaces el signo más
[email protected] es válido y se usa a propósito: mucha gente añade etiquetas con + para saber quién ha filtrado su dirección. Rechazarlo es una forma infalible de irritar a los usuarios técnicos. El patrón de arriba lo admite; déjalo así.
¿Por qué no usar el patrón «perfecto» de RFC 5322?
La especificación permite legalmente espacios entre comillas, comentarios entre paréntesis y otras monstruosidades. Un regex realmente completo ocupa miles de caracteres y aun así discrepa con servidores de correo reales. La única prueba de que una dirección funciona es que reciba un mensaje. Por tanto: patrón sencillo para detectar erratas más correo de confirmación para lo demás. Hacer de abogado del RFC en un regex es invertir el esfuerzo en la capa equivocada.

Extraer emails de un texto (¡es otra tarea!)

# sin anclas y con límites de palabra: buscar, no validar:
[\w.+-]+@[\w-]+\.[\w.-]+

re.findall(r"[\w.+-]+@[\w-]+\.[\w.-]+", big_text)
# validación = anclado ^...$. extracción = sin anclas. no los mezcles.
📚 Esta es una página de nuestra serie sobre regex. Los cinco conceptos, la trampa codiciosa y cuándo conviene no usar regex, con audio: Regex en 10 minutos →