Una lista llena de direcciones muertas cuesta más que los envíos que desperdicia. Cada rebote duro le dice a Gmail, Outlook y Yahoo que no sabes a quién escribes, y lo tienen en cuenta contra tu dominio y tu IP de envío. Si se acumula, la siguiente campaña acaba en spam, también para las direcciones buenas.
La verificación de email sirve para encontrar esas direcciones antes de que lo haga un proveedor de correo. Esta guía sigue una dirección a través de las cuatro etapas que ejecuta un verificador, en orden, y muestra qué parte de una respuesta de la API de BounceIntel rellena cada etapa. Al terminar deberías poder leer un resultado por tu cuenta en lugar de fiarte de una etiqueta de una sola palabra.
Qué es la verificación (y qué no es)
La verificación de email es una prueba automática que determina si una dirección puede recibir correo en este momento. Se apoya en dos fuentes: los registros DNS públicos y una breve conversación con el servidor de correo que recibiría el mensaje. No se envía ningún email. La conversación termina antes de que se transmita contenido alguno, así que la persona detrás de la dirección no ve nada.
Conviene ser igual de claro sobre lo que la verificación no puede decirte:
- Si una persona lee el buzón. Un buzón puede existir y estar abandonado. Eso lo responden los datos de interacción, no la verificación.
- Si la dirección seguirá funcionando el mes que viene. La gente cambia de trabajo y los buzones se eliminan. Un resultado describe el momento de la comprobación, y por eso cada resultado de BounceIntel incluye
score.freshness, defreshaexpired. - Si una dirección es una trampa de spam. Los dominios conocidos por operar trampas se marcan, pero una trampa bien hecha está diseñada para parecer una dirección real que funciona.
- Si tienes permiso para escribir a alguien. Es una cuestión de consentimiento, y ninguna prueba técnica puede responderla.
Etapa 1: sintaxis y normalización
La primera etapa nunca sale del verificador. Divide la dirección por la @ en una parte local y un dominio, y comprueba que ambas estén bien formadas. Una dirección que falla aquí se queda aquí: sin consulta DNS, sin conexión al servidor de nadie y con un resultado is_reachable: "invalid", el código de motivo invalid_syntax y una puntuación de 0.
Dos detalles deciden si una dirección poco habitual pasa:
- Los dominios internacionalizados como
münchen.dese convierten a su forma ASCII (xn--mnchen-3ya.de), y todas las etapas siguientes usan esa forma. - Las partes locales no ASCII como
josé@example.comse consideran no válidas. Entregarles correo requiere una extensión SMTP que la mayoría de servidores de destino no ofrece, así que en la práctica rebotan.
La misma etapa prepara dos cosas que puedes usar de inmediato. syntax.normalized_email da la forma canónica del buzón: en Gmail, los puntos y todo lo que va después de un + no cambian el destino, así que [email protected] se normaliza como [email protected], lo que facilita detectar duplicados en una lista. Y cuando el dominio está a una o dos letras de un proveedor conocido, syntax.suggestion propone la corrección probable (gmial.com pasa a gmail.com) y se añade el código de motivo possible_typo.
| Campo | Qué te indica |
|---|---|
syntax.is_valid_syntax | Si la dirección está bien formada |
syntax.username, syntax.domain | Las dos mitades, tal como se verificaron |
syntax.normalized_email | El buzón canónico, para eliminar duplicados |
syntax.suggestion | Una corrección probable de errata, o null |
Etapa 2: registros DNS y MX
Un dominio anuncia adónde debe ir su correo mediante registros MX. El verificador los consulta y la respuesta aparece en mx.records (los servidores de correo del dominio) y mx.accepts_mail. Un dominio sin registros MX no tiene adónde entregar, y el resultado lleva el código de motivo no_mx. Solo con eso se descarta una cantidad sorprendente de direcciones malas: dominios de empresa caducados, erratas que resultan estar registradas y dominios inventados escritos en formularios de registro.
En esta etapa también se compara la dirección con lo que se sabe de su dominio y de su parte local:
misc.is_disposablemarca los servicios de buzones desechables (código de motivodisposable).misc.is_role_accountmarca direcciones compartidas comoinfo@osupport@(role_account).misc.is_spam_trap_domainmarca dominios conocidos por operar trampas de spam (spam_trap).- Los proveedores gratuitos de consumo como Gmail se anotan con
free_provider.
El host MX también identifica el proveedor de correo que hay detrás del dominio, como Google Workspace o Microsoft 365. Eso importa para la siguiente etapa, porque cada gran proveedor responde a la verificación a su manera.

Etapa 3: la sonda SMTP
Esta es la etapa que separa una verificación real de una simple comprobación de formato. El verificador se conecta a uno de los hosts MX del dominio en el puerto 25 y empieza la misma conversación que cualquier servidor de envío:
- Se presenta con
EHLO. - Indica un remitente con
MAIL FROM. - Indica la dirección que comprueba con
RCPT TO. - Lee la respuesta del servidor para ese destinatario y cierra la conexión.
El mensaje en sí, el paso DATA, nunca ocurre. Lo que importa es cómo respondió el servidor en el paso 3:
- Aceptada (respuesta
250):smtp.is_deliverableestrue. - Rechazada por usuario desconocido:
smtp.is_deliverableesfalse, con el código de motivosmtp_undeliverable. - Rechazada porque la cuenta está desactivada:
smtp.is_disabledestrue(disabled_mailbox). - Rechazada porque el buzón está lleno:
smtp.has_full_inboxestrue(full_inbox).
En la misma conexión, BounceIntel pregunta después por un segundo destinatario: una dirección aleatoria de 15 caracteres en el mismo dominio que no puede existir. Si el servidor también la acepta, smtp.is_catch_all es true. Más abajo verás por qué importa.
"smtp": {
"can_connect_smtp": true,
"is_deliverable": true,
"is_disabled": false,
"has_full_inbox": false,
"is_catch_all": false
}
No todos los servidores responden con claridad. Algunos retrasan a propósito a los remitentes desconocidos con un rechazo temporal (greylisting), otros limitan la frecuencia, otros rechazan conexiones de redes que no reconocen y otros simplemente no responden a tiempo. Nada de eso es un veredicto sobre la dirección, y BounceIntel no finge que lo sea. El resultado pasa a unknown, y un código de motivo nombra lo que ocurrió: transient_smtp, smtp_policy_block, smtp_timeout, smtp_network, smtp_ambiguous o smtp_unreachable.
Etapa 4: puntuación y códigos de motivo
La última etapa convierte todas las señales de las tres primeras en algo accionable. score.score va de 0 a 100 y corresponde a una categoría: 80–100 es valid, 50–79 es risky, 1–49 es unknown y 0 es invalid. score.confidence y score.confidence_level (high, medium, low o very_low) indican cuántas pruebas respaldan ese número, y score.safe_to_send da la respuesta de sí o no.
La parte sobre la que construir es score.reason_codes. Enumera cada señal que influyó en el resultado como cadenas estables sobre las que tu código puede decidir, y score.sub_reason nombra la que fue determinante. Junto a ella, bounce_risk.action recomienda qué hacer (send, send_with_caution, verify_manually o do_not_send) y bounce_risk.risk_factors explica esa recomendación, cada factor con su peso.
Este es un resultado real para una dirección de soporte compartida en un dominio que acepta todo el correo, reducido a los campos de puntuación:
{
"input": "[email protected]",
"is_reachable": "risky",
"score": {
"score": 55,
"category": "risky",
"confidence_level": "low",
"reason_codes": ["catch_all", "role_account", "catch_all_high_risk"],
"sub_reason": "catch_all",
"safe_to_send": false
},
"bounce_risk": {
"action": "verify_manually",
"risk_factors": [
{ "signal": "smtp_is_catch_all", "contribution": 20, "description": "Corporate catch-all mailbox" },
{ "signal": "is_role_account", "contribution": 10, "description": "Role-based mailbox" }
]
}
}
En tu código, decide según la recomendación y guarda los códigos de motivo para quien revise la dirección más adelante:
const { bounce_risk, score } = await res.json();
if (bounce_risk.action === "do_not_send") {
suppress(email, score.reason_codes);
} else if (bounce_risk.action === "verify_manually") {
queueForReview(email, score.reason_codes);
} else {
accept(email);
}
La puntuación también tiene en cuenta el historial de tu propia cuenta con esa dirección en los últimos 180 días, y por eso una segunda comprobación puede volver con más confianza que la primera.
El punto ciego del catch-all
La etapa 3 tiene un límite que ningún verificador puede sortear. Algunos dominios están configurados para aceptar correo de cualquier dirección, exista o no. Pregunta a su servidor por jane.doe@ y dirá que sí; pregunta por una cadena de caracteres aleatorios y volverá a decir que sí. La conversación SMTP demuestra que el dominio recibe correo. No puede demostrar que exista el buzón que te interesa.
Para eso sirve la sonda con una dirección aleatoria. Cuando se acepta, BounceIntel marca el resultado como risky en lugar de safe, añade el código de motivo catch_all y gradúa el riesgo con un código de gravedad (catch_all_low_confidence, catch_all_medium_confidence o catch_all_high_risk) basado en pruebas como la configuración del dominio y los patrones de nombre ya verificados en esa empresa. Un verificador que llama «válidas» a estas direcciones está describiendo la cortesía del servidor, no el buzón.
Qué significan «safe / risky / invalid / unknown»
is_reachable es el resumen en una palabra de todo lo anterior. El verificador gratuito de este sitio muestra los mismos cuatro valores, con etiquetas traducidas.
is_reachable | Qué pasó | Qué hacer |
|---|---|---|
safe | El servidor aceptó el buzón y no apareció ninguna señal de riesgo | Enviar |
risky | El buzón parece existir, pero el dominio es catch-all, la dirección es desechable o genérica, el buzón está lleno o el dominio opera trampas de spam | Leer los códigos de motivo y decidir |
invalid | Sintaxis incorrecta, o el servidor rechazó o desactivó el buzón | Eliminarla |
unknown | El servidor no dio una respuesta útil: tiempo agotado, greylisting o bloqueo | Conservarla y volver a comprobarla más tarde |
Aquí es fácil equivocarse en dos cosas. unknown describe un servidor en un momento dado, no la dirección, así que borrar esas direcciones es tirar contactos buenos. Y risky agrupa situaciones muy distintas: un buzón lleno suele ser temporal, mientras que una dirección desechable nunca será de un cliente. La etiqueta es un resumen. La decisión corresponde a bounce_risk.action y score.reason_codes.
Cuándo usar tiempo real y cuándo masivo
Las cuatro etapas son las mismas en ambos casos. Lo que cambia es el momento.
La verificación en tiempo real, una dirección cada vez con POST /v1/check_email, va donde una dirección entra en tus sistemas: formularios de registro, pago, formularios de contacto comercial o un comercial escribiendo en el CRM. La persona sigue ahí, así que una errata detectada por syntax.suggestion se puede corregir en el momento en lugar de convertirse en un rebote la semana siguiente. Llama a la API desde tu servidor, nunca desde código del navegador con tu clave, y trata unknown como «aceptar y volver a comprobar más tarde» para que un servidor lento nunca bloquee un registro real.
La verificación masiva, con POST /v1/bulk o subiendo un CSV en el panel, va antes de un envío: una newsletter a una lista que llevaba tiempo sin usarse, una importación de una feria o de un nuevo CRM, o una revisión periódica de una base antigua. Cada fila vuelve con los mismos campos. Las listas se degradan a medida que la gente cambia de empresa, así que verifica todo lo que no se haya comprobado en unos meses antes de enviarle correo.
| Tiempo real | Masiva | |
|---|---|---|
| Endpoint | POST /v1/check_email | POST /v1/bulk y después consultar el trabajo |
| Mejor momento | Cuando se recoge la dirección | Antes de una campaña o tras una importación |
| Beneficio principal | Erratas corregidas con la persona todavía presente | Direcciones muertas eliminadas antes de rebotar |
Qué hacer con unknown | Aceptarla y volver a comprobar | Apartarla de este envío y volver a comprobar |
Comprueba una dirección y lee el resultado
Todo lo que muestra el verificador sale de la misma API a la que llamaría tu código. La documentación de la API describe cada campo de la respuesta, la verificación masiva cubre listas completas y los precios muestran cuánto cuesta un plan con acceso a la API.

