Dev.to AI 🤖 Ai 👁 0 📖 3 min read

n8n orchestrates, LangGraph writes, a human approves: an AI cold-email pipeline that can't spam

"AI SDR" demos usually end with an agent blasting a few hundred emails. In real B2B sales that burns your domain in a week, and the emails are full of claims nobody can back up. I built a lead-generation pipeline for an

"AI SDR" demos usually end with an agent blasting a few hundred emails. In real B2B sales that burns your domain in a week, and the emails are full of claims nobody can back up.

I built a lead-generation pipeline for an export manufacturer with three hard rules:

  1. Every claim in an email must come from sourced data, quoted from what the APIs returned.
  2. A rule checker rejects bad drafts and sends them back for a rewrite (max 2 times).
  3. Nothing is sent until a human clicks Approve.

Here is how the work is split, which I think is the useful part.

n8n does the plumbing, LangGraph does the thinking

n8n (55 nodes) handles everything deterministic:

  • Triggers (manual, schedule, webhook)
  • Apollo for finding people and enriching emails, Hunter for verifying them
  • Dedupe against what is already in the CRM, qualification filters
  • HubSpot (or a Google Sheet) as the CRM
  • An approval link per draft, an unsubscribe link, and a suppression list checked again right before sending
  • SendGrid (or Gmail / SMTP) to send, behind a SEND_ENABLED flag

A LangGraph service (FastAPI) does the parts that need a model:

research -> write -> check -> (rewrite, max 2) -> draft for approval
  • research writes a short note about the company, and every reason must carry a verbatim quote from the lead data, or it is cleared.
  • write drafts the email from that note only.
  • check is plain code, not another LLM: it blocks numbers that are not in the research or approved facts, unsupported claim phrases, placeholders and empty fields, a missing unsubscribe line, and over-long drafts.
  • Failing drafts go back to a rewrite step with the checker's reasons. After two failed rewrites the draft is flagged needs_human_fix, never sent.

The model is any OpenAI-compatible endpoint (OpenAI, DeepSeek, Qwen, OpenRouter), so you are not locked in.

Why the checker is code, not an LLM

An LLM grading an LLM tends to agree with itself. A regex and a list of allowed numbers does not. The checker is boring on purpose, and it is the reason I trust the drafts enough to show them to a salesperson.

Industry is a JSON file

Target industry, buyer type, product lines and selling points live in one profile file, and a small script turns it into the n8n variables. The kit ships with a battery-storage example and an LED-lighting example to show how to swap.

How I tested it

  • 21 pytest tests for the LangGraph service, 8 JS tests for the n8n Code nodes
  • A live run against a real n8n instance (1.123.87) with local mock Apollo / Hunter / HubSpot / SendGrid: 26/26 checks pass
  • 10 fake leads end to end: 6 drafts waiting for approval, 2 disqualified, 1 deduped, 1 blocked by the unsubscribe list

To be clear: these runs used mocked vendor APIs and a deterministic fake model. You bring your own Apollo, Hunter, HubSpot, SendGrid and LLM keys.

Get the template

The full kit (importable n8n workflow, LangGraph + FastAPI service, Docker Compose, tests, sample profiles) is here:

👉 B2B AI Lead Generation: n8n + LangGraph template, $29

I also wrote about a WhatsApp bot where the LLM is only allowed to pick an FAQ id: WhatsApp AI Customer Service Bot kit, $19.

Questions about splitting work between n8n and LangGraph are welcome in the comments.

📰 Read the original article on Dev.to AI

Originally published by Dev.to AI. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.