Hoja de referencia de regex para correos (con ejemplos resueltos)
Seis patrones de regex para correos, cada uno probado contra las mismas 15 direcciones. El simple que hace el 95 % del trabajo, el estricto con forma de RFC y el que detecta la ofuscación para protegerse del scraping. Con las trampas explicadas.
La regex simple (la que conviene usar)
[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}
Este es el patrón que usa casi todo extractor de producción. Acepta todo formato de correo del mundo real y rechaza todo lo que obviamente no es un correo. Estricto según la RFC no lo es, pero el rigor de la RFC no es lo que los sistemas reales necesitan.
Tres clases de caracteres, en orden:
- Parte local: letras, dígitos, punto, guion bajo, porcentaje, signo más, guion. Repetidos una o más veces.
- Dominio (todo lo que va antes del último punto): letras, dígitos, punto, guion. Repetidos una o más veces.
- TLD (después del último punto): solo letras, dos o más.
Casos de prueba — qué captura cada patrón
| Dirección | ¿Debería coincidir? | Regex simple |
|---|---|---|
alice@example.com | sí | coincide |
bob.smith+filter@example.co.uk | sí | coincide |
support_team@subdomain.company.io | sí | coincide |
x@y.museum | sí | coincide |
"weird local"@example.com | sí (RFC) | no coincide |
alice@ | no | no coincide |
@example.com | no | no coincide |
alice@example | no | no coincide |
not-an-email | no | no coincide |
La regex simple se salta patrones legales según la RFC pero nunca vistos en la práctica (partes locales entre comillas, comentarios incrustados). Sáltatelos. Perseguirlos agrega complejidad sin capturar direcciones reales.
La regex con forma de RFC (la que no conviene usar)
La regex completa de correos de la RFC 5322 ronda los 6400 caracteres. La versión más corta «con forma de RFC» a la que la mayoría recurre:
(?:[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])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-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])+)\])
Este patrón técnicamente acepta más direcciones legales. En la práctica, es más lento, más difícil de leer, más difícil de depurar y casi no captura direcciones que el patrón simple se salte. Úsalo solo cuando la postura legal del proyecto exija de forma explícita el cumplimiento de la RFC.
La regex que detecta la ofuscación
Para el texto donde las direcciones se ofuscan a propósito, ejecuta una pasada de preprocesamiento antes de la regex estándar:
// JavaScript
const deobfuscated = text
.replace(/\s*\[\s*at\s*\]\s*/gi, '@')
.replace(/\s*\(\s*at\s*\)\s*/gi, '@')
.replace(/\s+at\s+/gi, '@')
.replace(/\s*\[\s*dot\s*\]\s*/gi, '.')
.replace(/\s*\(\s*dot\s*\)\s*/gi, '.')
.replace(/\s+dot\s+/gi, '.');
// Ahora corre la regex de correos estándar sobre `deobfuscated`
Esto captura los patrones comunes: name [at] domain [dot] com, name (at) domain (dot) com, name AT domain DOT com. No capturará los correos ensamblados con JavaScript ni los renderizados como imagen. Esos necesitan herramientas distintas.
Sintaxis por lenguaje
El mismo patrón en cinco lenguajes:
JavaScript:
const re = /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g;
const matches = text.match(re) || [];
Python:
import re
re.findall(r'[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}', text)
Go:
re := regexp.MustCompile(`[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}`)
matches := re.FindAllString(text, -1)
Ruby:
matches = text.scan(/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/)
grep -E (POSIX):
grep -Eoi '[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}' file.txt
Los cinco producen el mismo resultado con la misma entrada. El escapado de la barra invertida es la única diferencia relevante. POSIX usa una sola barra invertida; algunos lenguajes usan doble barra invertida dentro de las cadenas literales.
Trampas comunes
- Puntuación al final. La regex se traga los puntos porque la clase del TLD los permite. Elimina los
.,;:)>}]que queden al final tras la extracción. - Coincidencia codiciosa entre varias líneas. Si la entrada no tiene espacios entre dos direcciones, una regex mal delimitada puede coincidir a través de ellas. Usa siempre límites de palabra o ánclala a caracteres que no sean de correo.
- Sensibilidad a mayúsculas. La RFC dice que la parte local distingue mayúsculas. Los sistemas reales la tratan sin distinguirlas. Pasa a minúsculas al extraer, salvo que tengas una razón específica para no hacerlo.
- Configuración regional. La regex usa ASCII
a-zA-Z. Para las direcciones internacionalizadas, cambia a las clases de propiedad Unicode:\p{L}para letras,\p{N}para dígitos.
Para la referencia más amplia sobre la extracción de correos, incluida la capa legal, mira Extracción de correos: la guía completa. Para el recorrido del flujo de trabajo, mira cómo extraer correos de cualquier texto.
Preguntas frecuentes
¿Qué regex para correos debo usar?
Casi siempre la simple: [a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}. Captura toda dirección del mundo real que te vayas a encontrar y rechaza todo no-correo evidente. La versión que cumple la RFC es demasiado permisiva para el uso práctico.
¿Por qué la regex se salta los correos que tienen un + ?
No debería. El patrón estándar incluye el + en la clase de caracteres de la parte local. Si tu regex se salta alice+filter@example.com, le falta el + en [a-zA-Z0-9._%+-]. Agrégalo.
¿Esta regex funciona en JavaScript, Python y Go?
Sí. Usa solo funciones de regex estándar de POSIX. Cada lenguaje tiene diferencias menores en la sintaxis de escapado (el \. se mantiene igual; algunos lenguajes necesitan \\). Mira la sección por lenguaje.
¿Por qué {2,} en lugar de solo {2,4} para el TLD?
Los TLD modernos van mucho más allá de cuatro caracteres: .museum tiene seis, .solutions tiene nueve, .international tiene trece. {2,} los maneja todos. Los límites de longitud fijos se saltan dominios reales.
¿Cómo uso esta regex en Excel o Google Sheets?
Ambos admiten regex con REGEXEXTRACT (Sheets) y Power Query (Excel). El patrón entra como una cadena literal. Escapa la barra invertida como \\ en la fórmula.
Seguir leyendo
Escrito por SAVI. Creamos las herramientas sobre las que escribimos. Prueba el Extractor de Correos que usamos en este artículo.