345 Follow-ups, Zero Respostas: Como Corrigimos o Outreach Automatizado

Paulo Rodrigues7 min de leitura

345 Follow-ups, Zero Respostas: Como Corrigimos o Outreach Automatizado

Gerimos uma pipeline de cold outreach automatizada para a ImparLabs. O sistema descobre empresas com websites desatualizados, analisa o stack tecnológico, e envia emails personalizados a oferecer os nossos serviços. Toda a infraestrutura é self-hosted — n8n para orquestração, PostgreSQL para dados, Groq para geração de emails com IA.

Após três semanas de operação, os números eram estes:

MétricaValor
Emails enviados (primeiro contacto)1.088
Respostas ao primeiro contacto10
Follow-ups enviados345
Respostas aos follow-ups0

Dez respostas dos emails iniciais. Zero dos 345 follow-ups. Nem uma única.

Os follow-ups deviam ser a força motriz de qualquer campanha de outreach. A maioria dos prospects precisa de 3-4 contactos antes de responder. Uma taxa de 0% significava que algo estava fundamentalmente partido.

A Encontrar a Causa Raiz

Comecei por ler os emails que o sistema estava a enviar. Os primeiros emails mencionavam descobertas específicas — "o seu site usa jQuery 2.2.4" ou "reparámos que o certificado SSL está em falta." Os follow-ups diziam coisas como "apenas a dar seguimento ao meu email anterior" e "podemos ajudar a melhorar o seu website."

Genérico. Esquecível. Indistinguível de spam.

O código contava a história. O endpoint dos emails iniciais usava execute_sql_json() com um query que fazia JOIN com a tabela tech_stacks — onde guardamos tudo o que sabemos sobre o website de cada prospect. Versão de jQuery, estado HTTPS, tempo de carregamento, versão do CMS, ano do copyright.

O endpoint de follow-up usava execute_sql() (uma função diferente, mais antiga) com um query sem JOIN algum à tech_stacks. A IA estava a gerar follow-ups "personalizados" com zero dados sobre o website real do prospect.

Quatro Problemas, Um Ficheiro

Assim que comecei a investigar, surgiram quatro problemas:

1. Sem Dados Técnicos nos Follow-ups

O query SQL obtinha o registo da campanha e o nome da empresa, mas nada da tech_stacks. O prompt da IA não recebia informação sobre os problemas do website do prospect. Tinha de inventar propostas de valor genéricas.

Correção: Adicionámos LEFT JOIN tech_stacks ts ON c.id = ts.company_id e selecionámos todas as colunas relevantes — has_https, is_mobile_friendly, jquery_version, cms, cms_version, copyright_year, load_time_ms, tech_outdated.

2. Parsing de Dados Inseguro

A antiga execute_sql() devolve texto delimitado por pipes — cada linha é uma string como 123|email@exemplo.com|Nome Empresa|assunto. Se o nome de uma empresa contém o caracter pipe (como "Café & Bar | Lisboa"), o parsing quebra silenciosamente. Os campos desalinham, e o email é enviado para o endereço errado ou com dados corrompidos.

Correção: Mudámos para execute_sql_json() que devolve dicionários. Sem mais divisões de strings, sem mais corrupção de campos.

3. Timing Fixo

Todos os follow-ups esperavam exatamente 7 dias independentemente da posição na sequência. O primeiro follow-up esperava 7 dias. O segundo esperava 7 dias. O terceiro esperava 7 dias. Sem progressão de urgência, sem variação de padrão.

Correção: Implementámos timing variável com uma expressão SQL CASE:

  • Passo 1 → 2: esperar 3 dias
  • Passo 2 → 3: esperar 5 dias
  • Passo 3 → 4: esperar 7 dias

Isto cria urgência natural — o primeiro follow-up chega enquanto o email inicial ainda está fresco, e os intervalos alargam-se à medida que a sequência progride.

4. Prompts Genéricos da IA

Mesmo com dados disponíveis, os prompts não instruíam a IA a usá-los de forma diferente por passo de follow-up. Todos os quatro ângulos recebiam a mesma instrução genérica.

Correção: Criámos uma função auxiliar (_summarize_tech_findings()) que converte dados técnicos brutos numa string resumo em português. Cada ângulo de follow-up recebe contexto específico:

  • Follow-up 2 (valor técnico): Referencia descobertas específicas — "jQuery v2.2.4 tem vulnerabilidades conhecidas"
  • Follow-up 3 (prova social): Usa indústria e localização — "empresas do seu sector em Lisboa já estão..."
  • Follow-up 4 (gancho final): Uma descoberta técnica afiada como argumento de fecho

A Armadilha dos NULL

Havia um quinto problema escondido na própria correção. Quando uma empresa não tem registo na tech_stacks (porque o enriquecimento ainda não correu), o LEFT JOIN devolve NULL para todas as colunas técnicas. A versão inicial de _summarize_tech_findings() verificava if not tech.get("has_https") — que trata NULL da mesma forma que False.

Isto significava que empresas que não tínhamos analisado receberiam emails a dizer "o seu site não tem HTTPS" quando simplesmente não sabíamos. A correção foi comparação estrita de identidade: if tech.get("has_https") is False — só sinalizar o que confirmar explicitamente.

A Testar o Que Importa

Esta pipeline não tinha testes automatizados. Cada alteração era verificada chamando a API manualmente e lendo a resposta. Para um sistema que envia centenas de emails a empresas reais, isto não é aceitável.

Adicionámos 111 testes cobrindo a lógica de negócio principal — escaping SQL, validação de email, limpeza de nomes de empresas, e o novo sumarizador de descobertas técnicas. Todas funções puras, sem conexões à base de dados, sem chamadas de rede. A suite completa executa em 0,19 segundos.

O insight chave: se a função precisa de uma conexão à base de dados para ser testada, a função está a fazer demasiado. Extrair a lógica, testar a lógica, confiar na infraestrutura.

A Lição

O mesmo modelo de IA, com a mesma estrutura de prompt, produz spam ou valor. A diferença está inteiramente nos dados que lhe damos.

Os nossos follow-ups passaram de "podemos ajudar a melhorar o seu website" para "o seu site ainda usa jQuery 2.2.4 — uma migração simples resolve vulnerabilidades conhecidas e melhora o tempo de carregamento." Mesma IA, mesmo template de prompt, resultado dramaticamente diferente.

Automação sem contexto é ruído. Se o outreach "personalizado" é apenas um template com um nome trocado, está a queimar leads. A infraestrutura para recolher dados sobre prospects só é útil se realmente os passar ao sistema que escreve os emails.

Colocámos a correção em produção e estamos a monitorizar resultados. A taxa de resposta dos follow-ups só pode subir a partir de 0%.


Esta pipeline funciona inteiramente em infraestrutura self-hosted — n8n, PostgreSQL, Groq AI — sob jurisdição europeia com conformidade GDPR. Nenhum dado de prospect sai dos nossos servidores. Se está a construir outreach automatizado para o mercado europeu, podemos ajudar a fazer bem.

Perguntas Frequentes

Porque é que emails de follow-up automatizados não recebem respostas?

A causa mais comum é personalização falsa — o email parece personalizado mas não contém dados específicos sobre o destinatário. No nosso caso, o query SQL não fazia JOIN com a tabela de análise técnica, por isso a IA gerava texto genérico apesar de termos dados detalhados disponíveis.

Como tornar emails de follow-up gerados por IA mais eficazes?

Alimentar a IA com dados específicos e verificáveis sobre cada prospect. Em vez de 'podemos melhorar o seu site', referenciar descobertas concretas como 'o seu site usa jQuery 2.2.4 que tem vulnerabilidades conhecidas.' Timing variável (3/5/7 dias) também cria urgência natural.

O que é timing variável de follow-up e porque importa?

Timing variável significa alterar o intervalo entre emails de follow-up com base na posição na sequência — por exemplo, 3 dias para o primeiro follow-up, 5 para o segundo, 7 para o terceiro. Isto cria uma sensação de urgência crescente e evita que o padrão pareça automatizado.

Pronto para automatizar o seu negócio?

Construímos ferramentas de IA e sistemas de automação para PMEs europeias — desde MVPs rápidos até sistemas em produção, sempre em conformidade com o GDPR.

it's human stuff

Insights semanais de IA para PMEs europeias. Sem exageros, apenas o que funciona.

Continue a Ler