How to build an AI cold email personalization workflow in n8n

Short answer

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

  1. 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.
  2. 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).
  3. 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.
  4. Optional news search. Another HTTP Request to a search API for "<company> news". This gives the model recent, specific hooks.
  5. 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.
  6. 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.
  7. Parse and validate. A Code node parses the JSON, clamps the score to 1–10, and marks the row error with the message if parsing fails.
  8. Filter by fit. An IF node: status = researched AND fit_score ≥ threshold AND email not empty.
  9. Create Gmail drafts. Gmail → Draft → Create with the subject and body. Drafts, not sends, keep a human in the loop.
  10. 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

PitfallFix
A missing credential on an optional node blocks the whole runDeactivate optional nodes until they're configured
Rows updated in the wrong placeMatch 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 textFall back to news results or manual notes
429 rate-limit errorsSmaller 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.

Skip the build

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.