Case Study

Concept Build

Cold Email Lead Recovery

Two connected n8n workflows that turn a raw Apollo/Apify lead scrape into personalized cold email drafts — including for the leads the scrape couldn't find an email for.

Concept Build — Not a Client Project

A self-directed build, not yet deployed for a named client. The writing half it sits on top of was tested against a real, verified 270-lead list, covered in The Cold Email Personalizer. The recovery chain described here is built and working.

Type
Concept Build — not a client project
Sector
Concept: Any outbound sales operation
Workflows
Two connected n8n workflows
Built
2026
Status
Built and working — not client-deployed
Core Feature
Two-tier email recovery & AI personalization

At a Glance

<50%
typical email match rate on a lead scrape
2 tiers
LinkedIn URL, then company domain
$0
cost per failed lookup
Fail-soft
a dead site or missed lookup never drops the lead

01

Executive Summary

A lead scrape is not the same thing as a contactable lead. This build is two connected n8n workflows: one handles any lead that already has a usable email, and a second sits in front of it to recover the leads that arrive with none — through a two-tier lookup chain — before handing them to the same writing path.

Apollo and Apify scrapes typically return valid emails for less than half of scraped leads. That back half is the part most outbound setups write off. Here it gets a second and third shot: a LinkedIn URL lookup, then a company-domain lookup, both of which cost nothing unless they land. The leads that come back with an email rejoin the same writing path as everyone else.

02

The Problem

Apollo and Apify reliably return names, titles, and companies, but a working email on every row is the exception. Most outbound setups either drop the emailless rows on the floor or have someone manually chase them down one LinkedIn search at a time. Both options cost something: a smaller addressable list, or an operator's time spent on a problem a workflow could absorb.

  • A scrape returns names, titles, and companies reliably — a working email on every row is the exception
  • Dropping the emailless rows shrinks the addressable list before outreach even starts
  • The manual alternative is chasing each one down through LinkedIn searches, one lead at a time
  • Either way the cost lands somewhere: a smaller list, or an operator's hours on repetitive lookup work

03

The Approach

Split the problem into two workflows instead of one. The base flow handles any lead that already has a usable email: scrape the company site for context, write a personalized draft with GPT-4.1-mini, save it for review. The recovery flow sits in front of it and only handles the leads the base flow would otherwise never see. Everything downstream of “lead has an email” stays a single shared path, so the recovery logic can change without ever touching the writing logic.

Order the fallback chain cheapest-and-most-likely first. A LinkedIn URL lookup runs before a company-domain lookup, and both only run after the free scrape data has already come up short. Anymail Finder only charges a credit on a fully verified match, so a failed lookup at either tier costs nothing. The ordering decision means the system can afford to try every lead without inflating cost on the ones it cannot recover anyway.

Fail soft, not hard, at every optional step. A dead company website does not block the run, it just means a slightly more generic email. A failed LinkedIn lookup does not drop the lead, it falls through to the domain search. The only leads that end up with no draft are the ones that arrive with neither a LinkedIn URL nor a company domain — genuinely nothing left to try, not a workflow giving up early.

04

Architecture

LayerImplementation
Lead sourceGoogle Sheets (Apollo/Apify export)
Orchestrationn8n — two workflows, manual trigger
Email recoveryAnymail Finder (LinkedIn-URL and domain+name lookups)
PersonalizationOpenAI GPT-4.1-mini, structured JSON output
Context enrichmentCompany website scrape, fails soft
Draft storageAirtable (Full Name, Email, Title, Subject, Body)

05

What It Does

Recovers the back half
the leads a scrape returns with no email get a two-tier lookup instead of being written off, so they stay addressable rather than counted as lost
$0 on failure
every recovery attempt is free unless it succeeds, so the fallback chain adds addressable leads without adding cost on the ones it cannot save
Fail-soft
a dead company site or a missed lookup never halts the batch; the only leads that end with no draft are the ones with neither a LinkedIn URL nor a company domain
2 chains
the recovery chain and the writing chain can each be improved or swapped independently — a third tier or a larger model on high-value segments are additive changes, not rewrites

06

Why This Matters

The interesting part is not the writing step, it is the ordering decision in front of it. Because a failed lookup costs nothing, the system can afford to try every lead. That single pricing detail is what makes recovering the back half of a scrape worth automating at all.

The instinct with a thin lead list is to buy more leads. Usually the cheaper move is to stop discarding the ones you already paid for. Half a scrape arriving without an email is not a data problem, it is a workflow that gives up one step too early. Two lookups and a fail-soft path are enough to close most of it.

Stack

n8nGoogle Sheets (Apollo/Apify export)OpenAI (GPT-4.1-mini)AirtableAnymail Finder
Soulwire Studio

Systems with soul: custom websites, AI automation, and the digital ecosystems behind them, built for mission-driven businesses.

© 2026 Soulwire Studio · Veteran-owned · San Antonio, TX