Um agente se cadastrando num serviço consegue talvez quarenta segundos de trabalho útil antes de chegar a uma tela que diz enviamos um código para o seu e-mail. Tudo o que vem depois depende de uma maquinaria que o agente normalmente não tem: um endereço que aceite e-mail, um jeito de saber que o e-mail chegou e um jeito de tirar seis dígitos de uma sopa de HTML escrita para o olho humano.
Há três tarefas escondidas nessa frase, e vale separá-las, porque a maior parte da dor vem de resolvê-las na ordem errada.
1. Um endereço que existe antes de você precisar dele
A abordagem ingênua é ligar o agente a uma caixa postal real: uma conta do Gmail com senha de app, ou uma conexão IMAP com uma caixa compartilhada do time. Funciona exatamente até você ter dois agentes. Aí um lê os códigos do outro, e a falha é não determinística e um tormento para depurar.
O que você realmente quer é um endereço descartável por agente e por tarefa, criado no momento em que é necessário e jogado fora depois. Isso significa que criá-lo tem que ser barato o bastante para fazer inline: sem painel, sem API key, sem humano no loop:
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
Essa chamada não tem autenticação. O token que volta é a credencial daquela caixa e de mais nada, e é essa propriedade que torna seguro entregá-lo a um agente: o raio de estrago de um token vazado é uma caixa descartável.
2. Saber que o e-mail chegou, sem loop de polling
É aqui que a maioria das implementações caseiras erra. O instinto é fazer polling: checar a caixa, dormir dois segundos, checar de novo. Funciona no seu notebook e é um risco em produção: você queima tokens a cada despertar e corre contra um código que normalmente expira em dez minutos.
O long-polling inverte isso. O agente faz uma única requisição que fica bloqueada até o e-mail chegar ou o timeout expirar:
curl -sS -H "Authorization: Bearer $TOK" \
"https://api.apumail.com/api/v1/inbox/$ADDR/wait?timeout=120"
Uma requisição. Um despertar. A conexão fica aberta e retorna no instante em que o listener SMTP aceita a mensagem. Para um agente isso importa mais do que para um serviço comum: cada polling extra é uma ida e volta ao modelo, e essas idas e voltas custam dinheiro de verdade e latência de verdade.
3. Tirar os dígitos
Esta é a parte que, silenciosamente, mais consome tempo de engenharia. Um e-mail de verificação é uma peça de marketing: tabelas aninhadas, pixels de rastreamento, um código embrulhado em três spans e uma tag font. Entregar isso a um LLM para "achar o código" funciona em cerca de 95% das vezes, o que é um número péssimo quando está no seu caminho crítico.
A versão viável é extrair no lado do servidor, na hora de salvar, antes de o agente
sequer ver a mensagem. O apumail roda a extração quando o e-mail é aceito e coloca
o resultado num campo otp da mensagem:
{
"messages": [{
"from": "noreply@stripe.com",
"subject": "Your Stripe verification code",
"otp": "482910"
}]
}
O agente lê .messages[0].otp. Sem parsing, sem prompt, sem
95%. O fluxo inteiro (criar, esperar, extrair) são três chamadas sem nenhum
envolvimento do modelo, o que significa que ele não tem como alucinar um código.
Tudo 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
Se o seu agente fala MCP, esses mesmos três passos são três chamadas de ferramenta e você pode pular o HTTP inteiro: veja e-mail temporário como servidor MCP. E se o muro que o seu agente encontrou foi um código por SMS em vez de um por e-mail, a mesma camada de espera/extração cobre números de telefone.