apumail / blog

Cómo reciben los agentes de IA los códigos de verificación OTP

La verificación por email es el primer muro con el que choca casi todo agente autónomo. El formulario de registro es fácil. Los seis dígitos que esperan en una bandeja que el agente no tiene, no.

14 de julio de 2026

Un agente que se registra en un servicio logra tal vez cuarenta segundos de trabajo útil antes de llegar a una pantalla que dice te enviamos un código a tu email. Todo lo que sigue depende de una maquinaria que el agente normalmente no tiene: una dirección que acepte correo, una forma de saber que el correo llegó y una forma de sacar seis dígitos de una sopa de HTML escrita para el ojo humano.

En esa frase se esconden tres tareas, y vale separarlas, porque la mayor parte del dolor viene de resolverlas en el orden equivocado.

1. Una dirección que existe antes de necesitarla

El enfoque ingenuo es conectar el agente a un buzón real: una cuenta de Gmail con contraseña de aplicación, o una conexión IMAP a una bandeja compartida del equipo. Funciona justo hasta que tienes dos agentes. Entonces leen los códigos del otro, y la falla es no determinista y un suplicio de depurar.

Lo que realmente quieres es una dirección desechable por agente y por tarea, creada en el momento en que se necesita y descartada después. Eso significa que crearla tiene que ser lo bastante barato como para hacerlo en línea: sin panel, sin API key, sin un humano en el ciclo:

INBOX=$(curl -sS -X POST https://api.apumail.com/api/v1/inboxes)
ADDR=$(echo "$INBOX" | jq -r .address)
TOK=$(echo "$INBOX" | jq -r .token)

echo "$ADDR"   # vivid-llama-4a2c@apumail.com

Esa llamada no lleva autenticación. El token que vuelve es la credencial de esa bandeja y de nada más, y esa es la propiedad que hace seguro entregárselo a un agente: el radio de daño de un token filtrado es una bandeja desechable.

2. Saber que el correo llegó, sin un bucle de sondeo

Aquí es donde fallan la mayoría de las implementaciones caseras. El instinto es sondear: revisar la bandeja, dormir dos segundos, revisar de nuevo. Funciona en tu laptop y es un riesgo en producción: quemas tokens en cada despertar y compites contra un código que normalmente expira en diez minutos.

El long-polling lo invierte. El agente hace una sola petición que queda bloqueada hasta que llega el correo o vence el timeout:

curl -sS -H "Authorization: Bearer $TOK" \
  "https://api.apumail.com/api/v1/inbox/$ADDR/wait?timeout=120"

Una petición. Un despertar. La conexión queda abierta y responde en el instante en que el listener SMTP acepta el mensaje. Para un agente esto importa más que para un servicio normal: cada sondeo extra es una ida y vuelta al modelo, y esas idas y vueltas cuestan dinero real y latencia real.

3. Sacar los dígitos

Esta es la parte que silenciosamente se come más tiempo de ingeniería. Un correo de verificación es una pieza de marketing: tablas anidadas, píxeles de seguimiento, un código envuelto en tres spans y una etiqueta font. Pasárselo a un LLM para que "encuentre el código" funciona cerca del 95% de las veces, que es una cifra pésima cuando está en tu ruta crítica.

La versión manejable es extraerlo del lado del servidor, al guardar, antes de que el agente vea el mensaje. apumail ejecuta la extracción cuando acepta el correo y deja el resultado en un campo otp del mensaje:

{
  "messages": [{
    "from": "noreply@stripe.com",
    "subject": "Your Stripe verification code",
    "otp": "482910"
  }]
}

El agente lee .messages[0].otp. Sin parsing, sin prompt, sin 95%. Todo el flujo (crear, esperar, extraer) son tres llamadas sin ninguna participación del modelo, lo que significa que no puede alucinar un código.

Todo junto

# 1. provision
INBOX=$(curl -sS -X POST https://api.apumail.com/api/v1/inboxes)
ADDR=$(echo "$INBOX" | jq -r .address)
TOK=$(echo "$INBOX" | jq -r .token)

# 2. use $ADDR in the signup form, then block until the mail lands
CODE=$(curl -sS -H "Authorization: Bearer $TOK" \
  "https://api.apumail.com/api/v1/inbox/$ADDR/wait?timeout=120" \
  | jq -r '.messages[0].otp')

# 3. submit $CODE
echo "$CODE"   # 482910

Si tu agente habla MCP, esos mismos tres pasos son tres llamadas a herramientas y puedes saltarte el HTTP por completo: mira email temporal como servidor MCP. Y si el muro con el que chocó tu agente fue un código por SMS en vez de uno por email, la misma capa de espera/extracción cubre números de teléfono.

Pruébalo, sin registro

Un solo POST sin autenticación devuelve una dirección funcional y su token.

curl -sS -X POST https://api.apumail.com/api/v1/inboxes