TL;DR
We needed outbound for LoopSuit, so we built the machine ourselves instead of renting a stack of SaaS seats. It merged 4,535 lead rows into 2,953 unique leads across 4 niches, researched every company with Claude for $0.07 per 100 leads, and sent about 750 emails from one warmed inbox. The biggest lesson had nothing to do with copy. Our first lists used guessed email addresses and bounced up to 68%, so we built a gate that every list now has to pass. Here is the build, step by step, with the real numbers.
The Starting Point
LoopSuit builds AI systems for other businesses. Before we sell outbound to anyone, we wanted to run it on ourselves and see exactly where it breaks. The goal was simple: send cold email that reads like one person wrote it, to people who might genuinely need what we build, without burning our domain.
We picked four niches: Canadian founders, franchise operators, restaurant groups, and local clinics plus home services. Each niche got its own offer pack, so the copy speaks to one kind of business at a time instead of everyone at once.
The constraint shaped everything. We sent from one warmed inbox, capped at 35 to 50 emails a day. At that volume, every bad address and every lazy line costs real capacity. So the system is built around list quality and one true sentence per lead, not raw volume.
The Stack We Actually Use
No Clay seat, no per-row enrichment credits. Most of the work runs in a Python pipeline on a laptop, and the only paid call inside it is the model.
Apollo exports and Apify's Google Maps scraper supply the raw rows. Apollo gives names and titles. Maps gives real businesses with real websites and, as it turned out, far better email addresses. Every source names its columns differently, so a normaliser maps them all to one schema before anything else runs.
A seven-stage pipeline cleans, enriches, scrapes, summarises, personalises and assembles a send file. It saves progress every 10 leads, so a dropped connection mid-run never costs a rerun. It can restart or jump to any stage with one flag.
Claude reads each company's homepage and returns what they do, who they serve and one signal worth writing about. Then it writes an observation plus a matching bridge line. A QA pass rejects anything that sounds like a bot.
Instantly handles sending, warm-up, daily caps and reply detection. Plain text, tracking off, and the sequence stops the moment someone replies.
Step 1: Pull and Merge the Lists
We pulled leads from Apollo exports and Google Maps scrapes across the US and Canada. Once all four niches were loaded, we had 4,535 lead rows spread across 20 files.
Many of those rows were the same person. The office manager at a dental clinic can show up in an Apollo export and again in a Maps scrape, once in capital letters and once with a trailing space. Send to both and you look careless on day one.
The dedupe step fixes that:
- Every email is trimmed and lowercased into a match key, and matching rows merge into one person
- Role inboxes like info@ and office@ get flagged
- Addresses are grouped by domain, which catches a pattern we'll come back to: a company where every address is first.last, which usually means the addresses were guessed
- Every new batch is checked against everyone already contacted, so nobody gets the same first email twice
Result: 4,535 rows became 2,953 unique leads. Roughly a third of the raw list would have been double-sent or wasted.
Step 2: Research Every Company with Claude
Personalisation only works if it is about them. So the pipeline reads each company's homepage (title, meta description, headline, first paragraphs), five sites at a time, and hands the text to Claude Haiku.
Claude returns four fields: what they do, who they serve, a category, and one signal. The signal is the useful part. For a dental clinic it might be: books new patients online, but nothing brings back the ones who stopped coming. The prompt is roughly:
Read this company's homepage text. Return JSON with four fields: - what_they_do: one plain sentence - who_for: who their customers are - category: the kind of business - signal: one tension worth writing about, in their words where possible If the page gives you nothing specific, return signal = null. Do not guess.
The null matters. When there is no real signal, the lead gets a line from a pre-approved fallback bank for its niche instead of an invented compliment. Every lead gets a line, and no line pretends to know something it doesn't.
Speed and cost were the pleasant surprise. A logged run of 100 leads went through every stage in 5 minutes 36 seconds, and the model cost for the whole batch was $0.07.
Step 3: Write the Sequence
We kept it to three plain-text steps. Each one has a single job:
- Day 0: The personal line plus a bridge. The line is an observation about them. The bridge comes from the same pain, so the pivot to what we do never feels bolted on. Then a short ask.
- Day 4: A short bump in the same thread. Two lines.
- Day 9: A last note. Polite, short and final.
An illustrative opener for a dental clinic: "At Northwind, the booking page fills this week's chairs and does nothing for patients who haven't been in since spring. Most clinics have a few hundred of those sitting in the file, and nobody owns them."
Before anything ships, a QA pass checks every line: short enough, no dashes, no pitch in line one, and no bridge reused inside the same batch. Lines that fail get repaired or swapped for a fallback.
Step 4: Protect the Inbox
Deliverability is the least exciting part of the build and the one that decides whether anything else matters. The rules we run:
- Separate sending domain: never the main one. If a sending domain gets hurt, the business domain doesn't.
- SPF, DKIM, DMARC: configured on every sending domain before the first email.
- Warm-up first: weeks, not days, before a real send.
- A hard daily cap: ours ran at 35 to 50 sends a day from a single inbox.
- Plain text, tracking off: tracking pixels and rewritten links are one more thing for a spam filter to dislike.
Step 5: Build a Gate Before Anything Sends
This is the part we learned the hard way. Free contact scrapers often don't find a real address. They guess one, usually first.last@company.com. The guesses look fine in a spreadsheet. They bounce in real life.
When we split bounces by list source, the gap was stark:
Same inbox, same sending window. The difference was where the addresses came from. A list that bounces two out of three wastes most of a capped day before a single person reads anything, and it teaches the mail providers to distrust you.
So we built a gate. Every list now passes a free triage first: syntax, role inboxes, free mail, a mail-server (MX) lookup, and a check for guessed patterns. On its first run it triaged 2,385 addresses: 2,037 cleared to send, 335 flagged risky and 13 dead.
Clearing triage is not the finish line. The next rule is that only addresses a paid verifier marks valid can load into the sender. A bounce costs more than a verification ever will. The full gate and pipeline are laid out in our cold outreach case study.
Step 6: Sort the Replies
All mailboxes feed one inbox. Every reply gets one of five labels: interested, objection, timing, wrong person or not interested. Each label maps to a next step, and a human approves every answer before it goes.
That is a deliberate choice. At our volume, reading each reply takes minutes a day, and a wrong automatic answer to an interested prospect costs far more than that. Automatic labelling is the next build, and it will still stop for approval on anything that looks like a yes.
Want this built for your business?
Book a free 30-minute call. We'll look at your buyers, your list sources and your current outreach, and show you what this system would look like pointed at your market.
What the Numbers Actually Say
Counted from the pipeline's own files and the sender's logs:
And the honest part: replies have been few, and none has turned into a booked meeting yet. We are not going to dress that up with a reply rate.
What the run did prove is where the leverage sits. Research and writing are solved, fast and cheap. List quality is the whole game. A guessed-email list burns most of a day's capped sends before anyone reads a word, so the copy never gets a fair test. Fix the list first, then judge the copy.
The next step is more warmed inboxes on separate domains, fed only verified lists, so there is enough volume to measure copy changes properly.
What It Costs to Run
The costs, in plain terms:
- Research and writing: about $0.07 in model cost per 100 leads. At that rate, researching all 2,953 leads costs roughly $2.
- Pipeline: Python, pandas and Flask on a laptop. CSV files, no database, no per-row enrichment credits.
- Lead sources: Apollo exports and Apify's Google Maps scraper, both usable on free or entry tiers at this scale.
- Sending: an Instantly plan plus the sending domains and inboxes. These are the real fixed costs, and they grow with the number of inboxes, not the number of leads.
- Verification: a paid verifier, charged per address. Cheap per address, and far cheaper than a burned domain.
The expensive part of outbound is not the AI. It is the infrastructure, and the time lost sending to addresses that were never real.
What We'd Do Differently
If we started again tomorrow:
- Verify before the first send, not after. The guessed-email lists should never have reached the sender. Every bounce there was a capped send that could have gone to a real person.
- Choose sources with real addresses. Maps-sourced lists bounced 3.6 to 8.1%. Guessed first.last lists bounced 59.8 to 68.1%. Source choice mattered more than any line of copy.
- Warm more inboxes from day one. One inbox at 35 to 50 a day is too little volume to learn quickly which copy works. Set up several domains and warm them in parallel.
- Build reply sorting before launch. Replies arrive in week one. The labels and next steps should already exist when they do.
This is the same system we now build for clients, under their brand. We set up the domains, the list gate, the copy engine and the reply inbox, then run it with you. For how the pipeline handles dedupe and research at scale, see the lead engine case study.