Cuatro preguntas que comparten una palabra
«¿Es válida esta dirección de correo?» no es una sola pregunta. Son cuatro, se vuelven más difíciles en ese orden, y la última es la única que alguien quería en realidad que se respondiera — por eso hay tanto código de validación elaborado sobre la primera y callado sobre el resto.
Aquí están, en el orden en que se las encuentra un formulario de registro.
- ¿Tiene forma de dirección?
- Una comprobación de sintaxis. Se ejecuta en el navegador, no cuesta nada, y detecta la coma mal escrita y la
@que falta. Es la única capa que puede rechazar algo honestamente por sí sola — e incluso así debería rechazar mucho menos de lo que rechazan la mayoría de los patrones. - ¿Podría ese dominio recibir correo siquiera?
- Una comprobación de DNS. Una sola consulta dice si algo, en algún lugar, está dispuesto a aceptar correo para la parte que va después de la
@. Detecta un nombre de dominio al que le falta una letra y un dominio que caducó el año pasado, y no puede decirte absolutamente nada sobre el buzón. - ¿Existe ese buzón?
- Una comprobación SMTP — y la que a esta guía le va a llevar más tiempo advertirte que no te fíes. Se puede preguntar. La respuesta es a menudo un sí educado de un servidor que acepta cualquier nombre, o un fallo temporal deliberado, o una aceptación seguida de un rebote minutos después.
- ¿Es su dirección?
- Nada del lado técnico puede responder a esto. Una dirección puede ser impecable, entregable y de otra persona — escrita mal por un carácter, o escrita a propósito para superarte. Solo un mensaje que llega y se usa lo cierra.
Las tres primeras son baratas y prueban poco. La cuarta es la única que se merece el nombre, y es la que cuesta un mensaje. Todo lo que viene a continuación trata de aprovechar bien las tres baratas para que la cara no se desperdicie.
Capa uno: el patrón, y las cuatro cosas que no puede saber
No existe una expresión regular oficial para una dirección de correo, y no puede existir. El RFC 5322 define una gramática, no un patrón, y esa gramática permite comentarios entre paréntesis, espacios en blanco plegados y cadenas entre comillas que contienen casi cualquier carácter — nada de lo cual debería aceptar un formulario de registro real, y todo lo cual tiene que aceptar un patrón fiel a ella.
Lo que sí existe es una definición deliberadamente más estrecha que los navegadores ya implementan: la que da la especificación HTML para un campo <input type="email">. Es un compromiso deliberado y no una transcripción del estándar, es a lo que ya está sujeto tu formulario antes de que se ejecute ni una línea de tu código, y es lo bastante corta para leerla de un tirón:
/^[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])?)*$/Usa esa, o usa la que ya trae tu plataforma. Las cuatro de abajo son la misma capa, y elegir una es una decisión más pequeña que lo que hagas después:
| Dónde estás | La comprobación que ya tienes | Lo que hace que quizá no esperes |
|---|---|---|
| En el navegador, sin código alguno | <input type="email" required> | Aplica el patrón de arriba antes de que tu JavaScript llegue siquiera a ver el campo, y muestra el mensaje en el propio idioma del visitante. |
| En PHP, sin instalar nada | filter_var($a, FILTER_VALIDATE_EMAIL) | Más estricta que la de HTML: insiste en que haya un punto en el dominio, así que rechaza una dirección que solo funcionaría dentro de una única máquina. |
| En Python, con un paquete pequeño | email_validator.validate_email(a) | Hace la sintaxis y, si se lo permites, la consulta de dominio de la capa dos — las dos capas baratas detrás de una sola llamada. |
| En Java o Kotlin, mediante Bean Validation | @Email | Muy permisiva a propósito. Es una anotación pensada para detectar lo obviamente erróneo, y acepta sin problema un dominio que nunca ha existido. |
Uses la que uses, lo que importa es sobre qué se queda callada. Un patrón que devuelve true te ha dicho una cosa y cuatro no-cosas.
- No que el dominio exista
- Una dirección en un dominio que nadie ha registrado nunca pasa todos los patrones de esta sección. No se ha consultado nada y no se ha contactado con nada; ninguna expresión regular ha hecho jamás una petición de red.
- No que el buzón exista
- Incluso en un dominio real, el patrón no tiene ninguna opinión sobre la parte anterior a la
@. Esa parte pertenece solo al servidor receptor, y es precisamente lo que el DNS nunca te va a decir. - No que sea entregable
- Un dominio puede tener un registro impecable y un servidor de correo que lleva un mes apagado. La sintaxis es una propiedad de una cadena; la entregabilidad es una propiedad del mundo en el momento en que pulsas enviar.
- No que pertenezca a quien la escribe
- La dirección mala más frecuente en cualquier base de datos es una real, entregable, propiedad de alguien que nunca se registró — porque se escribió mal una letra, o porque el formulario se rellenó con una mentira de aspecto creíble.
Qué es legal, y qué se rechaza por error
La mayoría de los fallos de validación no son direcciones malas que consiguieron colarse. Son personas que no pudieron registrarse, y nunca aparecen en ningún registro que nadie lea — el formulario dijo que no, y se fueron a otra parte. Estas seis son las que más lo provocan.
| Lo que rechazan los formularios | ¿Es legal? | Qué es en realidad |
|---|---|---|
Un signo más, como en name+shop@example.com | Legal, y muy utilizado | Direccionamiento con signo más: un solo buzón, con una etiqueta que su dueño eligió para poder ver quién la filtró. Rechazarlo le dice a un visitante cuidadoso exactamente qué tipo de formulario es este. |
Un apóstrofo, como en o'brien@example.com | Legal, y el apellido de alguien | Uno de la docena de signos de puntuación que permite la parte local. Cuando un formulario lo rechaza, el motivo casi nunca es la dirección — es un fallo de escapado más adelante que nadie quiso encontrar. |
Una terminación que nadie conoce, como en .dev o .photography | Legal, y hay bastante más de mil | Un patrón con una lista de terminaciones escrita a mano ya estaba desactualizado el día en que se escribió, y empeora cada año sin que nadie se dé cuenta. |
| Un dominio sin ningún punto | Legal, e inútil para ti | Una dirección como root@localhost es válida dentro de una máquina y no significa nada en un formulario público. Es el único caso en el que los verificadores estrictos de la plataforma tienen razón al rechazar. |
Letras no latinas, como en 用户@例子.广告 | Legal, con una salvedad | Las direcciones internacionalizadas existen y se extienden despacio. Que tu propia infraestructura de correo pueda enviar a una de ellas es una pregunta aparte — pero un campo que se niega a aceptar los caracteres la ha respondido por todo el mundo, para siempre. |
Mayúsculas antes de la @ | Legal, y no te corresponde cambiarlo | El estándar deja las mayúsculas y minúsculas de la parte local en manos del servidor receptor. Casi todos los servidores las ignoran; los que no lo hacen son aquellos de los que nunca vas a tener noticias. |
Y tres números, que merece la pena escribir directamente en tu código porque no cambian:
- 64 caracteres
- Lo máximo que puede medir la parte anterior a la
@. Cualquier cosa más larga no es una dirección larga, es que no es una dirección. - 255 caracteres
- Lo máximo que puede medir el dominio, puntos incluidos. Nada legítimo se ha acercado nunca a esa cifra, y el límite está aquí sobre todo para que tengas uno.
- 254 caracteres
- Lo máximo que puede medir la dirección completa cuando la transporta un servidor — que es menos que la suma de los dos números anteriores. Este es el que hay que poner en la columna de la base de datos y en el
maxlengthdel campo.
Capa dos: una consulta, y lo que resuelve
La parte que va después de la @ es un dominio, y un dominio o bien tiene dónde poner el correo, o no lo tiene. Una sola consulta DNS responde eso en unos pocos milisegundos, y es la comprobación de mayor valor de toda esta guía — porque el error que detecta, un nombre de dominio escrito ligeramente mal, es con diferencia el fallo real más frecuente que existe.
$ dig +short MX example.comUna respuesta significa que se ha nombrado un host. Que no haya respuesta no significa que no haya correo: un dominio sin registro MX pero con un registro A sigue recibiendo, porque los remitentes recurren a él. Hay cuatro resultados posibles, y solo dos de ellos son fallos.
| Lo que devuelve la consulta | ¿Puede recibir? | Qué debería hacer el formulario |
|---|---|---|
| Uno o más registros MX | Sí | Acéptala. Esta es la inmensa mayoría de las direcciones, y no merece la pena hacer nada más antes de enviar. |
Sin MX, pero con un registro A o AAAA | Sí, por reserva | Acéptala. Esto es poco habitual y totalmente legal, y los remitentes van a entregar ahí. Rechazarla convierte una dirección que funciona en un cliente perdido. |
Un único registro cuyo valor completo es 0 . | No, y a propósito | Recházala, y di por qué. Eso es un MX nulo: el dueño del dominio ha publicado, de la única forma que existe para publicarlo, que aquí no se recibe correo. |
| El dominio no resuelve en absoluto | No | Recházala, y ofrece lo más parecido. Un NXDOMAIN en un nombre que un humano escribió hace treinta segundos es casi siempre una letra equivocada. |
Donde esta comprobación sale mal nunca es la consulta en sí. Es dónde se colocó la consulta — en el camino crítico, en cada pulsación de tecla, con un fallo que bloquea el envío. Seis reglas la mantienen útil:
- Ejecútala cuando el campo esté terminado, no mientras se escribe. Una consulta cuando el foco sale del campo, o una al enviar. Una consulta por cada pulsación de tecla es una consulta por cada pulsación de tecla.
- Pasa el dominio a minúsculas primero. Al DNS le da igual, pero a tu caché no: dos formas de escribir el mismo dominio son una sola consulta, no dos.
- Pregunta por el MX, y recurre al
Acomo reserva. Dos consultas, de las cuales solo la segunda es condicional. Una librería que solo comprueba el MX va a rechazar dominios que funcionan. - Guarda la respuesta en caché unos minutos. Un puñado de dominios explica la mayoría de los registros en cualquier sitio, así que la mayoría de las consultas dejan de ser consultas.
- Falla en abierto. Si el resolutor agota el tiempo de espera, acepta la dirección. Un mal minuto en tu proveedor de DNS nunca debe convertirse en un formulario que rechace a todo el mundo.
- Sugiere una corrección; nunca la apliques. Cuando el dominio está a una letra de uno común, ofrece la corrección como algo en lo que hacer clic. Reescribir en silencio lo que alguien escribió es cómo un enlace de confirmación acaba en manos de un desconocido.
La consulta tiene un coste que merece la pena conocer: es el primer momento en que tu formulario le habla al mundo exterior sobre algo que escribió un visitante. Donde eso importa, la alternativa es saltarse esta capa por completo y dejar que el propio mensaje sea toda la comprobación.
Capa tres: preguntarle al servidor, y por qué la respuesta no es una respuesta
Existe una forma de preguntarle a un servidor de correo si va a aceptar una dirección concreta sin enviarle nada. Abre la conversación, nombra un remitente, nombra el destinatario, lee la respuesta a ese único comando, y cuelga antes del mensaje:
220 mx1.example.com ESMTP ready
EHLO checker.example.net
250 mx1.example.com
MAIL FROM:<probe@example.net>
250 2.1.0 Ok
RCPT TO:<someone@example.com>
250 2.1.5 Ok
QUIT
221 2.0.0 ByeEl 250 después de RCPT TO es lo que en el fondo vende todo servicio de verificación de direcciones del mundo. Merece la pena ser precisos sobre lo poco que vale.
- Un dominio catch-all dice que sí a todo
- Un dominio configurado para aceptar cualquier nombre — que es lo que hace este servicio, y lo que hacen muchísimos dominios de empresa — responde
250a una dirección que nadie ha usado jamás. La respuesta es cierta, y no es información. - Un servidor cuidadoso dice
450a propósito - El greylisting rechaza el primer intento de un remitente desconocido y le pide que vuelva poco después. Un remitente real lo hace; una sonda nunca lo hace. Ese fallo temporal es una no-respuesta deliberada, e interpretarlo como «ese buzón no existe» es exactamente el error que está diseñado para producir.
- Algunos servidores aceptan primero y rechazan después
- Los grandes proveedores suelen aceptar el mensaje durante la conversación y decidir sobre él más tarde, lo que convierte un rechazo en un rebote que llega minutos después de que tu sonda diera el visto bueno.
- Algunos servidores dicen que no a todo el que no reconocen
- Un servidor que ha decidido que tu dirección es un desconocido puede rechazar al destinatario por motivos que no tienen nada que ver con el destinatario. Lo que mediste fue tu propia reputación, no su buzón.
- Y gasta la reputación que se supone que protegías
- Una conexión que nombra destinatarios y nunca envía nada tiene exactamente la forma de una recolección de directorio, porque es una. Hacerlo en volumen desde tu propia dirección es la vía más rápida hacia una lista de bloqueo — y un remitente bloqueado es aquel cuyos mensajes genuinos dejan de llegar.
Hay un caso concreto en el que la sonda es realmente útil: una sola dirección, comprobada a mano, en un dominio que administras o que tienes permiso para tocar. Como paso dentro de un formulario de registro es lenta, con frecuencia está equivocada, y a veces perjudica precisamente lo que se añadió para proteger.
Direcciones de rol, dominios desechables, y la lista que estás a punto de comprar
Entre la consulta de dominio y el mensaje real se sitúa una familia de comprobaciones que no tienen nada que ver con la validez. Tratan de si quieres esta dirección, que es una decisión de negocio disfrazada de decisión técnica — y solo por eso merece la pena separarla de las tres capas que la rodean.
- Direcciones de rol
- Nombres como
info@,support@yadmin@. Son reales, y suelen ser un buzón compartido en lugar de una persona, lo que los convierte en un mal sitio para cualquier cosa que tenga una contraseña detrás. Merece la pena señalarlas. Rara vez merece la pena rechazarlas. - Dominios desechables
- Direcciones como las que reparte este sitio, en dominios que existen para ser desechados. Comprobarlas contra una lista pública de ellos es razonable, siempre que seas honesto contigo mismo sobre que toda lista de este tipo está incompleta y algo desactualizada el mismo día que la descargas.
- Direcciones de proveedores gratuitos
- Algunos formularios de empresa rechazan cualquier cosa que no sea un dominio corporativo. Eso es una política, a veces es la correcta, y merece estar escrita como una política — una frase que el visitante pueda leer — en lugar de escondida dentro de algo llamado validación.
- Erratas de dominios habituales
- El nombre de un proveedor conocido con una letra equivocada. Esta es distinta de las otras tres: no es una política, detecta un error genuino, y la persona siempre lo agradece. Es la única entrada de esta lista que merece la pena construir.
Las tres primeras comparten una propiedad que las hace difíciles de juzgar: puedes medir lo que dejan pasar y no puedes medir lo que cuestan.
Aquí tenemos un interés evidente, así que aquí va la versión honesta. Si detrás de tu formulario hay una prueba gratuita con algo caro enganchado, rechazar los dominios desechables te va a ahorrar dinero y deberías hacerlo. Si es un boletín, una descarga, o una cuenta que alguien paga, sobre todo estás penalizando a los precavidos — y los precavidos son quienes leen lo que envías.
Capa cuatro: el mensaje que es la comprobación
Todo lo anterior estrecha el campo. Nada de ello establece el único hecho que importa — que esta dirección llega a la persona que tienes delante — y solo hay una cosa que lo hace: enviar algo ahí, y comprobar que se usa.
Este es el bucle que ya tiene casi todo registro y que la mitad trata como una formalidad:
- Acepta la dirección con una sola comprobación permisiva. El patrón del navegador, y nada más entre el visitante y el botón.
- Crea la cuenta sin verificar. Nada de retener el formulario, nada de una pantalla de «pendiente»: la persona ya está dentro, y lo único que todavía no puede hacer es el puñado de cosas para las que la dirección realmente hace falta.
- Envía un mensaje con un enlace o código de un solo uso. Uno, con caducidad, ligado a esa cuenta y a esa dirección y a ninguna otra.
- Deja que el enlace sea la prueba. Un clic, o un código introducido de vuelta, es toda la verificación. Nada más en esta guía produce una respuesta ni remotamente tan sólida.
- Dales una forma de volver atrás. Un «reenviar» visible, y una forma de cambiar la dirección sin perder la cuenta — porque el motivo más habitual por el que un enlace nunca se pulsa es un error tipográfico que la persona ahora por fin puede ver.
- Caduca las que nadie confirmó. Una limpieza discreta tras un plazo fijo evita que los errores tipográficos y las direcciones desechables se acumulen en una lista en la que nadie confía.
Lo cual crea un problema práctico, y es la razón por la que existe este sitio. Ese bucle es ahora el camino más importante del producto, y probarlo significa recibir correo real en una dirección que controlas — una y otra vez, dentro de un pipeline, sin que ningún humano abra un buzón.
Una dirección en uno de los dominios públicos no necesita registro ni clave, y lo que llegue ahí se puede leer por HTTP un segundo después:
$ curl -sG https://grabmail.io/api/v1/mailbox \
--data-urlencode "address=signup-42@grabmail.io"A partir de ahí, una suite de pruebas puede recorrer todo un flujo de verificación de principio a fin, o se puede apuntar aquí un dominio propio para que cada ejecución obtenga una dirección que nunca ha existido antes. Los mensajes se conservan 5 días y después se eliminan, que es la vida útil correcta para un fixture de pruebas y la equivocada para un buzón.
Qué poner en el formulario, en la práctica
Condensado, en el orden en que se ejecuta el código:
- Recorta, y solo recorta. Los espacios en blanco en cualquiera de los extremos son un artefacto de pegar texto y nunca son intencionados. Nada más de la cadena te corresponde cambiar.
- Compara con un patrón permisivo. El del navegador, o el de tu plataforma. Rechaza la
@que falta y la coma mal escrita, y no rechaces nada más. - Limita la longitud a 254. Un solo número, en la columna y en el campo, y toda una clase de entrada de la que puedes dejar de preocuparte.
- Consulta el dominio, fuera del camino crítico, fallando en abierto. MX y después
A, en caché, y nunca un motivo para bloquear un envío que de otro modo habría funcionado. - Ofrece una corrección; no la impongas. Estar a una letra de un dominio común es una pregunta que hacer, no un hallazgo sobre el que actuar.
- Envía el mensaje. Eso es la validación. Todo lo anterior era triaje.
- Di qué ha ido mal, con palabras. Que es la parte que decide si alguien termina o no:
| Qué ha pasado | Lo que suelen decir los formularios | Qué decir en su lugar |
|---|---|---|
La cadena no tiene ninguna @ | «Introduce una dirección de correo válida» | «Una dirección de correo necesita una @ — ¿querías decir nombre@example.com?» |
| El dominio no resuelve | «Introduce una dirección de correo válida» | «No encontramos ese dominio. ¿Está bien escrito?» |
| El dominio está a una letra de uno común | Nada en absoluto; el formulario se envía | «¿Querías decir…?», con la dirección corregida como un botón para pulsar |
| Está en una lista de bloqueo que decidiste usar | «Introduce una dirección de correo válida» | «Para esto necesitamos una dirección que todavía puedas leer el mes que viene.» |
| El mensaje salió y nunca se confirmó | Nada en absoluto; la cuenta se queda ahí | «Enviamos un enlace a esa dirección. ¿No ha llegado? Reenvíalo, o cambia la dirección.» |
Fíjate en cuántas filas dicen lo mismo, y lo dicen mal. «Introduce una dirección de correo válida» es el mensaje por defecto en todas partes porque es cierto en todos los casos y útil en ninguno: en tres de las cinco filas la dirección era válida, y quien la escribió no tiene forma de averiguar en cuál de las filas está.
La versión corta
- Recorta la cadena. No le cambies nada más.
- Compárala con un patrón permisivo — el del navegador o el de tu plataforma — y no sigas más allá. No escribas el tuyo propio.
- Rechaza cualquier cosa por encima de 254 caracteres, y guarda una columna de ese tamaño.
- Consulta el MX del dominio, recurre al
Acomo reserva, guárdalo en caché, hazlo fuera del camino crítico, y acepta la dirección cuando la consulta falle. - Rechaza un dominio que no resuelve y un dominio que publica un MX nulo. Acepta todo lo demás que te dé el DNS.
- Ofrece una sugerencia de ortografía cuando el dominio se parezca mucho a uno conocido. Nunca la apliques tú mismo.
- Decide aparte, y por escrito, si vas a bloquear direcciones desechables o de rol — y por qué.
- Envía un mensaje con un enlace de un solo uso, trata el clic como la verificación, y facilita reenviar y corregir la dirección.
- Prueba ese bucle contra un buzón real, incluidos los caminos en los que falla, y elimina las cuentas sin confirmar según un calendario.
Nueve líneas, y las dos últimas son las únicas que establecen algo. Las otras siete existen para que el mensaje al final de ellas merezca la pena enviarse.
Preguntas
¿Existe una expresión regular oficial para las direcciones de correo?
No, y no puede haberla. El RFC 5322 da una gramática, no un patrón, y un patrón fiel a ella aceptaría espacios entre comillas y comentarios entre paréntesis que ningún proveedor emite. Usa la que define la especificación HTML para un campo de correo, o el verificador que ya traiga tu plataforma, y dedica el esfuerzo que ahorres al mensaje de confirmación.
¿Puedo comprobar si una dirección de correo existe sin enviar nada?
Puedes preguntar; no puedes saberlo. Un dominio catch-all acepta cualquier nombre, el greylisting responde con un fallo temporal deliberado, los grandes proveedores aceptan durante la conversación y rebotan después, y un servidor que no te reconoce puede rechazarte por motivos que tienen que ver contigo y no con el destinatario. Sondear en masa también pone tu dirección de envío en listas de bloqueo.
¿Es válida la dirección name+tag@example.com?
Sí. El signo más es un carácter permitido normal en la parte local, y en la mayoría de los grandes proveedores además redirige al buzón que va antes de él, que es lo que hace útil el direccionamiento con signo más. Un formulario que lo rechaza está rechazando direcciones legales, y anunciando algo sobre sí mismo al hacerlo.
¿Las direcciones de correo distinguen mayúsculas de minúsculas?
El dominio nunca las distingue. La parte anterior a la @, según el estándar, queda en manos del servidor receptor — y en la práctica todos los grandes proveedores ignoran las mayúsculas. Guarda una copia en minúsculas para detectar duplicados, y envía a la cadena exactamente como se escribió.
¿Cuánto puede medir una dirección de correo?
64 caracteres antes de la @, 255 para el dominio, y 254 para la dirección completa tal como la transporta un servidor. El último de esos tres es el número que hay que usar: ponlo en la columna de la base de datos y en el campo, y toda una clase de entrada deja de ser tu problema.
¿Debería bloquear las direcciones de correo desechables?
Si detrás de una prueba gratuita hay algo caro, sí — y acepta que cualquier lista que uses está incompleta. Para un boletín, una descarga o una cuenta de pago, las personas que rechazas son sobre todo las precavidas, y nunca las vas a ver en ningún registro. Merece la pena leer el análisis completo del compromiso antes de instalar un paquete que tome la decisión por ti.
¿Cómo pruebo un flujo de verificación de registro sin un buzón real?
Envía a una dirección en un dominio público desechable y léela de vuelta por la API — sin registro, sin clave, y una dirección nueva en cada ejecución. Para una suite que necesite cientos, apunta un dominio propio a un buzón catch-all e inventa una dirección por cada prueba. El recorrido completo está en probar un flujo de verificación de correo de principio a fin.


