How to build an AI cold email personalization workflow in n8n
Use n8n to chain: Google Sheets (leads) → HTTP Request (fetch each prospect's website) → Code (strip HTML, build a grounded prompt) → LLM call returning JSON (hook, first line, 3 emails, fit score) → IF (fit threshold) → Gmail: create draft → Google Sheets: update row. Keep a human review step: create drafts, never auto-send.
What you need
- n8n (Cloud or self-hosted)
- A Google Sheet with columns such as
first_name, email, title, company, website, notes, status - An OpenAI (or Anthropic) API key
- A Gmail account connected to n8n
- Optional: a search API (e.g. Tavily) for recent news
The workflow, node by node
- Trigger + Config. Start with a Manual or Schedule trigger, then a Set node holding your offer, ICP, CTA, tone and signature. Keeping these in one node makes the workflow reusable.
- Get leads. A Google Sheets → Get row(s) node filtered on
status = new, followed by a Limit node so each run processes a safe batch (e.g. 25). - Fetch the website. An HTTP Request node with response format "text", a 15-second timeout, and "continue on error". Some sites block bots, and one failure shouldn't stop the batch.
- Optional news search. Another HTTP Request to a search API for "<company> news". This gives the model recent, specific hooks.
- Build the prompt. A Code node strips scripts and tags, truncates to ~6,000 characters, and fills a prompt template with seller context plus prospect research.
- Call the LLM in JSON mode. An HTTP Request to the chat completions endpoint with
response_format: {type: "json_object"}. Ask for: research_summary, personalization_hook, first_line, fit_score, fit_reason, email_1_subject, email_1_body, email_2_body, email_3_body. Turn on retries and batching to avoid rate limits. - Parse and validate. A Code node parses the JSON, clamps the score to 1–10, and marks the row
errorwith the message if parsing fails. - Filter by fit. An IF node: status = researched AND fit_score ≥ threshold AND email not empty.
- Create Gmail drafts. Gmail → Draft → Create with the subject and body. Drafts, not sends, keep a human in the loop.
- Write back. Google Sheets → Update row, matched on
row_number(safer than matching on email), with status, emails, score and timestamp.
The prompt rules that matter most
- Ground every claim. "Use only the research provided. If it's thin, say so, use a role-based hook, and cap fit_score at 5."
- Ban clichés. "No 'I hope this finds you well', 'I came across', 'quick question'."
- Constrain length. Email 1: 50–90 words. Follow-up: 30–60 words with one new angle. Breakup: 20–45 words.
- Force structure. JSON mode plus an explicit list of keys makes parsing reliable.
Common pitfalls
| Pitfall | Fix |
|---|---|
| A missing credential on an optional node blocks the whole run | Deactivate optional nodes until they're configured |
| Rows updated in the wrong place | Match updates on row_number, not email |
| Generic "personalization" | Add news search, put seller notes in the sheet, sharpen the ICP |
| JavaScript-only websites return little text | Fall back to news results or manual notes |
| 429 rate-limit errors | Smaller batches and a batch interval on the LLM node |
FAQ
Can n8n send the cold emails automatically?
It can, but we recommend creating Gmail drafts and reviewing them. AI can misread a website, and a human check protects your domain reputation and brand.
Which model should I use?
Any chat model that supports JSON output. A small, low-cost model is usually enough for research summaries and short emails. Check your provider's current pricing.
How many leads per run?
Start with 2 to test, then batches of about 25. Increase only if you see no rate-limit errors.
The Cold Email Research Agent is this workflow, tested and ready to import, with a setup guide (about 15 minutes on n8n Cloud). $19/month on Starter, 7-day free trial.