Case Study
Concept BuildThe Cold Email Personalizer
A lead-to-draft outreach system that scrapes real company context and writes personalized cold emails in Soulwire's voice, tested against a real, verified 270-lead list.
Concept Build — Not a Client Project
A self-directed build, rebuilt from an earlier version with real data, real bug fixes, and Soulwire's own voice. The lead sourcing and draft figures below come from an actual run against a real, verified list. It has not yet been deployed for a named client, and the pipeline deliberately stops at Airtable rather than sending.
At a Glance
01
Executive Summary
This build turns a raw lead list into a folder of cold email drafts that each reference something real about the business they are going to. Every lead's company domain gets scraped for actual page copy before the writing model sees the row, so the model's job is narrowed to connecting what is actually there rather than guessing what a company like this probably does.
It was tested end to end against a real, verified list: 500 raw leads sourced across eight target industries, cleaned and deduplicated down to 270 unique leads with verified emails. Every draft in the tested batch traced back to something actually on the lead's website, with zero invented details. The pipeline stops at Airtable on purpose. Nothing sends without a human reading it first.
02
The Problem
Cold email personalization tends to fail in one of two directions. The cheap version is mail-merge: swap in a name and company, keep the same six sentences for every lead, and hope volume covers for the fact that it reads like a template. The expensive version throws a model at the problem and asks it to personalize based on the company, which sounds better until it starts inventing specifics it has no way of knowing: a product line the company does not have, a recent expansion that never happened.
- A prospect who gets an email that's wrong about their own business trusts the sender less than one who got a generic template
- Manually researching each lead's site for one honest hook works, but it doesn't scale past a handful of sends a day
- The model needs real, defensible context at list volume, without quietly filling gaps with plausible-sounding fiction
03
The Approach
Scrape before write, not instead of it. Every lead's company domain gets scraped for real homepage or about-page copy before the writing model ever sees the row. The model's job is narrowed to summarizing and connecting what is actually here, not guessing what a company like this probably does.
A hallucination bug traced to its root, not patched over. An earlier version of this workflow had a quiet failure: when a scrape failed, the error message itself got passed downstream as if it were page content, and the writing model dutifully personalized against garbage. The fix was not a better prompt. It was making the scrape step fail loudly and skip the row cleanly, so the writing model only ever sees real content or nothing at all.
Airtable as the review gate, not the send button. Every generated draft, subject and body both, lands in Airtable next to the lead's info. Nothing connects to a sending tool at this stage. That is a deliberate seam: the system is scoped to get you from raw list to a batch of drafts worth reading, and the decision to actually send stays a human one.
Dedupe before the list ever loads, not after drafts exist. Leads get deduplicated by email before they enter the sheet the workflow reads from. That is what turned 500 raw scraped leads into a clean list of 270, rather than 500 rows with a chunk of quiet duplicates burning API calls twice.
04
Architecture
| Layer | Implementation |
|---|---|
| Lead sourcing | Apify (microworlds/leads-finder), an Apollo-alternative scraper requiring no Apollo login |
| Filtering | Job title, company size (1–10 / 11–20 employees), US-based, eight target industries, verified-email status only |
| Automation | n8n, single batch-loop workflow |
| Context gathering | Per-lead website scrape (homepage/about-page copy) |
| Writing | GPT-4.1-mini, one generation per lead, voice-and-fact-fenced system prompt |
| Review | Airtable draft table, human approval before any send tool is connected |
05
Results
These come from an actual run against a real, verified lead list, not modeled math. They are still concept-build results rather than a client engagement outcome.
06
Why This Matters
The interesting work here was not the writing step. It was the bug. A scrape that failed silently and handed its own error message to the model looks fine in testing: you get a draft, it reads like an email, nothing throws. It is only wrong. Fixing that at the root instead of writing a cleverer prompt is the difference between a batch you skim and approve, and a batch you have to fact-check line by line.
The ban on inventing facts is what makes the review step cheap. Because the model can only write from what was actually scraped, a human reading the batch is checking tone, not accuracy. That is also why this build stops at Airtable rather than wiring a sender in: getting to drafts worth reading is one problem, and deciding to send is a different one that belongs to a person.
This build used a real, verified lead list end to end. Names and businesses referenced in sample outputs elsewhere are illustrative rather than the original test data, out of respect for the privacy of leads who did not opt into being a public case study.
Stack

