Como depurar “Enviado, mas não recebido” na visão do time de produto
Poucas frases dão tanta dor de cabeça quanto: “Aparece como enviado, mas eu não recebi”. Do lado do usuário, parece simples: ele clicou, o sistema confirmou, e nada chegou. Do lado do produto, isso pode ser qualquer coisa: atraso de fila, problema de autenticação, bounce silencioso, filtro do provedor, reputação de domínio/IP, webhooks perdidos, template quebrado, rate limit, ou até o destinatário olhando a caixa errada.
A boa notícia é que dá para investigar com método. Este guia é para times de produto: como estruturar triagem, que evidências pedir, quais métricas e logs devem existir, e como transformar um caso confuso em hipóteses testáveis e um plano de correção.
Por que esse problema é diferente (e por que produto precisa liderar)
“Não recebi” costuma ser uma falha de cadeia, não de um único componente. O time de produto entra porque a questão não é só técnica: é também experiência, confiança e conversão. Se um e-mail de verificação falha, o usuário não “espera”: ele abandona. Se um e-mail de reset não chega, o usuário acha que o sistema é inseguro. Se um e-mail transacional some, o suporte vira gargalo e o CAC “vaza” pelo ralo.
Produto precisa garantir três coisas: observabilidade (ver o que aconteceu), responsabilidade (quem age em cada etapa) e comunicação (o que o usuário vê quando dá errado).
Defina o que “enviado” significa no seu produto
Antes de depurar, alinhe o vocabulário. Em muitos produtos, “enviado” na UI significa apenas: “o backend aceitou o pedido e colocou na fila”. Em outros, significa “o provedor aceitou”. Em outros, significa “foi entregue na caixa do destinatário” (o que quase nunca é garantível).
Para evitar confusão interna e com o usuário, vale adotar estados claros: Solicitado (user action), Aceito (backend validou), Enfileirado, Enviado ao provedor, Aceito pelo provedor, Entregue (quando houver confirmação), Bounced, Bloqueado, Rejeitado, Spam/Quarentena (quando detectável).
Se o produto só exibe “enviado” quando está no estágio “aceito”, você está plantando a semente do ticket. Produto não precisa “prometer entrega”, mas precisa prometer a verdade.
Triagem rápida: perguntas que economizam horas
1) Qual e-mail, qual horário, qual fluxo?
Parece básico, mas é o que mais falta no primeiro contato. Peça: endereço do destinatário (com domínio), horário aproximado, fuso, tipo de e-mail (verificação, reset, convite, cobrança, recibo, marketing), e o contexto (primeiro envio ou reenvio). Em times de produto, isso vira um mini-formulário no suporte: sem isso, o time “caça” no escuro.
2) O usuário olhou spam, promoções e abas?
No Brasil, especialmente com Gmail e Outlook, o e-mail pode cair em Spam, Promoções ou até ficar escondido em filtros. Antes de chamar de incidente, crie um checklist simples para o suporte orientar: procurar pelo remetente, pelo assunto, por palavras-chave, e validar se há regras de filtro configuradas.
3) O domínio do destinatário tem histórico de bloqueio?
Alguns domínios corporativos têm políticas mais agressivas (filtros internos, quarentena). Se a maior parte dos casos vem de um domínio específico, isso sugere bloqueio por reputação ou política do receptor. É uma pista forte para priorizar autenticação e reputação.
4) O usuário está usando e-mail temporário?
Em produtos com onboarding rápido, parte dos usuários usa e-mail temporário. Esses endereços expiram, não suportam certos anexos, ou têm infraestrutura que pode atrasar recebimentos. Se esse for um cenário comum, o produto pode guiar: “use um e-mail permanente para recuperar conta”. Isso reduz tickets e melhora a taxa de sucesso em fluxos críticos.
Monte o “trace” do envio: um ID para governar todos
Se você pudesse escolher uma única melhoria estrutural para esse problema, seria: um ID de rastreio por mensagem visível e consistente em todo o pipeline. Esse ID precisa nascer no produto (no momento da ação do usuário) e atravessar: backend, fila, worker, provedor de e-mail, webhooks de evento, e armazenamento de eventos.
Do ponto de vista de produto, o ideal é ter: message_id (interno), provider_message_id (do provedor), e ligação com o usuário/conta e o fluxo (reset, verify etc). Assim, qualquer caso vira uma busca objetiva: “o que aconteceu com esta mensagem?”
Onde geralmente quebra: mapa do pipeline
Para depurar, pense em camadas. Em cada camada, há sintomas típicos e “provas” que você consegue coletar.
Camada A: Produto/UI e Backend (antes da fila)
- Validação incorreta: e-mail mal formatado ou normalizado errado (ex.: espaços, maiúsculas, caracteres especiais).
- Deduplicação agressiva: usuário clicou reenviar e o sistema bloqueou sem avisar (“já enviamos”).
- Rate limit interno: API retorna sucesso, mas descarta silenciosamente.
- Bug de template: renderização falha e o worker “engole” a mensagem.
Aqui, produto deve exigir que “sucesso” na UI só apareça quando houver uma evidência mínima: por exemplo, “solicitação registrada”, e um status consultável.
Camada B: Fila e workers
- Atraso: backlog alto, picos, jobs lentos, concorrência baixa.
- Falhas e retries: a mensagem falha e reentra em retry por minutos.
- Poison messages: um payload específico quebra sempre (caracteres, encoding, template).
- Configuração: worker não está consumindo uma fila, ou está consumindo o ambiente errado.
Sintoma clássico: usuário reclama “não recebi” e, horas depois, chega tudo junto. Esse é um cheiro de fila/worker.
Camada C: Provedor de e-mail (API SMTP/HTTP)
- 429 / rate limit: provedor recusa por volume.
- Rejeição por política: domínio sem autenticação adequada, remetente inconsistente, conteúdo suspeito.
- Erros temporários: timeouts, DNS, problemas de rede.
Produto precisa garantir que a equipe tenha acesso ao status do provedor por message_id, e que eventos sejam armazenados com consistência.
Camada D: Entrega no destinatário (onde você tem menos controle)
- Spam/quarentena: entregue “tecnicamente”, mas invisível ao usuário.
- Bloqueio por reputação: IP ou domínio marcado.
- Políticas corporativas: gateways internos seguram a mensagem.
- Greylisting: atrasos intencionais para combater spam.
Essa camada é onde times se perdem. Não dá para “garantir inbox”. Dá para aumentar as chances com autenticação, reputação e conteúdo consistente.
Checklist de evidências: o que pedir (sem virar “ping-pong”)
Para o suporte coletar e produto acelerar a investigação, padronize o pacote mínimo:
- E-mail do destinatário e domínio (ex.: gmail.com, outlook.com, empresa.com).
- Horário aproximado do envio e do reenvio (se houve).
- Fluxo (verificação, reset, convite, receipt etc).
- Captura de tela do produto mostrando a ação (quando aplicável).
- message_id interno (se existir) e status exibido.
- Se chegou depois, quanto tempo demorou.
- Se caiu no spam e se o usuário moveu para a caixa de entrada.
Isso transforma “não recebi” em um caso rastreável, e evita investigações “no feeling”.
Instrumentação que produto deve exigir
Se o time depende de logs manuais em servidores, você sempre vai estar atrasado. Produto deve tratar entrega de e-mail como um fluxo crítico e exigir telemetria de ponta a ponta.
Métricas (dashboards simples, mas obrigatórios)
- Taxa de aceitação no backend (solicitações válidas vs inválidas).
- Backlog da fila e tempo médio na fila (p95 e p99).
- Taxa de envio ao provedor e latência (worker → provedor).
- Taxa de bounce (hard vs soft) por domínio de destinatário.
- Taxa de reclamação (quando disponível) e sinais de spam.
- Taxa de entrega (delivered) e de eventos perdidos (webhook gap).
Logs estruturados (para busca por caso)
- event=message_requested com user_id, fluxo, timestamp.
- event=queued com queue_name e job_id.
- event=provider_send_attempt com payload checksum e resultado.
- event=provider_accepted com provider_message_id.
- event=delivery_event (delivered/bounced/blocked/spam) via webhook.
O objetivo é que alguém do time consiga responder em minutos: foi enfileirado? foi aceito pelo provedor? houve bounce? houve atraso?
Autenticação e reputação: o lado “invisível” que derruba entregabilidade
Quando a taxa de “não recebi” cresce sem mudanças óbvias no produto, muitas vezes o problema é entregabilidade. Do ponto de vista de produto, o tema parece “infra”, mas o impacto é 100% produto: onboarding trava, reset falha, e churn sobe.
SPF, DKIM e DMARC (o trio que você precisa respeitar)
Sem entrar em implementação detalhada, pense assim: SPF diz quem pode enviar por você; DKIM prova que a mensagem não foi adulterada e que o remetente é legítimo; DMARC define a política quando SPF/DKIM não batem, e melhora a confiança. Se isso está mal configurado, provedores podem aceitar e “sumir” com o e-mail em filtros.
Reputação de domínio e IP
Se vocês enviam muita coisa (ou enviam conteúdo que parece “promo”), a reputação sofre. Mesmo e-mails transacionais podem ser afetados. Sintoma típico: Gmail entrega bem, mas domínios corporativos não; ou o contrário. Outro sintoma: de um dia para o outro, o volume “parece normal”, mas a entrega cai.
Conteúdo e template também pesam
Links encurtados, excesso de imagens, palavras “gatilho”, HTML malformado, ou inconsistência entre From e domínio real podem aumentar suspeita. Produto pode ajudar padronizando templates, reduzindo variações, e garantindo que e-mails críticos sejam “clean”: texto claro, poucos links, e um CTA principal.
Hipóteses comuns e como testar (do jeito que produto entende)
Hipótese 1: atraso de fila
Teste: olhe o tempo na fila (p95/p99). Compare horário do clique do usuário com horário do “provider_accepted”. Se a diferença é grande, o problema está entre backend e worker. Correção: aumentar concorrência, reduzir tempo do job, dimensionar filas, e colocar alertas de backlog.
Hipótese 2: provedor recusando silenciosamente
Teste: verifique respostas de API e logs de erro. Se há 4xx/5xx, categorize por tipo e domínio. Correção: retries com backoff, limites por domínio, e fallback para um segundo provedor em e-mails críticos.
Hipótese 3: bounce por domínio específico
Teste: agrupe bounces por domínio do destinatário e por tipo (hard/soft). Se um domínio dispara, pode ser reputação ou política do receptor. Correção: ajustar autenticação, aquecer envio, revisar conteúdo e, se necessário, contato com o receptor (em B2B).
Hipótese 4: usuário não encontra porque caiu em spam/promoções
Teste: peça ao usuário que procure pelo remetente e confirme se está no spam. Se muitos casos aparecem no spam, há um sinal de reputação/conteúdo. Correção: melhorar autenticidade, consistência de remetente, e templates mais “transacionais”. Além disso, produto pode ajustar microcopy: “verifique Spam/Promoções”.
Hipótese 5: bug de template/encoding
Teste: compare casos que falham com variáveis do template (nome com acento, caracteres especiais, emoji, idioma). Um erro de encoding pode quebrar o job e impedir o envio. Correção: validação de template, testes automatizados, e fallback para texto simples quando necessário.
O que o produto pode mudar hoje para reduzir reclamações
1) Pare de prometer “enviado” cedo demais
Se o usuário vê “enviado” no momento do clique, mas o e-mail ainda nem saiu do sistema, o produto está criando uma frustração inevitável. Mostre algo mais honesto: “Solicitação registrada” e um estado “em processamento”. Em fluxos críticos, vale oferecer um status com tentativa de reenvio e tempo estimado.
2) Adicione orientação contextual
Em verificação e reset, um texto curto ajuda muito: “Se não chegar em alguns minutos, verifique Spam/Promoções e tente reenviar.” É simples, mas reduz tickets, porque o usuário sente que o produto “prevê” a falha.
3) Botão de reenvio com limites e transparência
Reenvio infinito pode virar abuso e piorar reputação. Reenvio limitado com contagem regressiva funciona. Mas não bloqueie sem explicar. Se houver limite, diga: “Você pode reenviar em X segundos”. Transparência reduz irritação.
4) Alternativa de verificação
Dependendo do produto, oferecer um segundo canal (SMS, autenticação por app, ou link dentro do produto) pode salvar a conversão. Nem sempre é viável, mas para fluxos com alto impacto, vale considerar.
5) Suporte com “código do caso”
Se o usuário abre ticket, ele pode informar um código que mapeia para o message_id. Isso corta metade do tempo de triagem e melhora a percepção de profissionalismo.
Como conduzir um incidente sem virar caos
Quando o volume de reclamações sobe, produto precisa operar como “central de comando”: medir impacto, priorizar fluxos críticos e coordenar comunicação.
Passo 1: delimitar o impacto
- É um fluxo específico (ex.: reset) ou todos?
- É um domínio específico (ex.: hotmail/outlook) ou geral?
- Começou depois de uma mudança (template, provedor, DNS, deploy)?
- Há atraso (chega depois) ou não chega nunca?
Passo 2: ativar “war room” com dados
Sem dashboard e trace, vira gritaria. Com dashboard e trace, vira investigação. Um canal com engenharia, suporte e produto, olhando os mesmos números, resolve mais rápido.
Passo 3: comunicação para o usuário (sem prometer demais)
Se houver falha real, avise no produto e/ou status page: “Podem ocorrer atrasos no envio de e-mails”. E dê alternativa: reenviar, mudar e-mail, tentar outro canal, ou suporte. O objetivo é manter confiança enquanto a correção acontece.
Exemplo rápido (história curta, bem real)
Um SaaS brasileiro começou a receber tickets de “não recebi o e-mail de convite”. Produto achou que era template. Engenharia achou que era o provedor. O suporte só repetia “veja o spam”. Quando colocaram um trace por message_id, ficou claro: as mensagens estavam ficando 30 a 40 minutos na fila nos horários de pico. O sistema mostrava “enviado” no clique, mas o worker não dava conta.
Resolveram em duas frentes: aumentaram a concorrência do worker e mudaram a UI para “processando”. Resultado: queda grande nos tickets e aumento de conversão de convites aceitos, porque o usuário parou de desconfiar que “não funcionava”.
Checklist final para times de produto
- Definição clara do que “enviado” significa na UI.
- Estados do envio com rastreio por message_id.
- Dashboards: backlog, latência, bounce, delivered, webhook gap.
- Runbook com perguntas de triagem e pacote mínimo de evidências.
- Autenticação bem cuidada (SPF/DKIM/DMARC) e consistência de remetente.
- Templates estáveis e testados (inclusive com caracteres PT-BR).
- UX de reenvio com transparência e limites.
- Plano de incidente: medir impacto, coordenar times, comunicar sem exageros.