AI Lead Machine Agent
AI Lead Machine Agent

A digital marketing agency was spending hours each day on manual lead generation: searching Google Maps for local businesses, hunting down contact emails, writing individual outreach messages, and tracking send status in a spreadsheet. The whole cycle — from identifying a prospect to hitting send — required constant human attention at every step.
We built an n8n agent workflow that takes a single form submission and delivers a logged, sent cold email for every qualified lead with no further human involvement.
The Workflow
Trigger: Lead Machine Form
Node 1 - On Form Submission (formTrigger) Presents a web form titled "Lead Machine." Collects four fields: Business Type, Location, Lead Number (how many results to pull), and Email Style (Friendly / Professional / Simple). On submission, all four values are passed downstream to the scraping stage.
Stage 1: Lead Scraping
Node 2 - HTTP Request → Apify Actor POSTs to the configured Apify Google Maps scraper endpoint. Passes Business Type as the search term, Location as the geographic query, and Lead Number as the result cap. Returns a list of business listings with name, category, address, phone, and website where available.
Stage 2: Lead Filtering
Node 3 - Filter (website exists) Drops any record where no website field is present. Only businesses with a known web presence move forward — these are the records where email extraction is possible.
Stage 3: Email Extraction
Node 4 - Information Extractor (Google Gemini) For each filtered lead, sends the website URL to an n8n LangChain Information Extractor node. The prompt instructs the model to scrape the site and return a single, correctly formatted email address.
Node 5 - Google Gemini Chat Model
Powers the Information Extractor. Connected via the ai_languageModel channel. Handles the website scrape and contact identification task.
Stage 4: Email Validation
Node 6 - IF Node: Valid Email Check
Checks whether the extracted value contains @. Records with a valid email address continue to the logging branch. Records without a usable email are routed to a no-operation terminal — no further processing occurs for those leads.
Stage 5: Lead Logging
Node 7 - No Operation Terminal node for leads where extraction returned no valid email. Silently exits.
Node 8 - Append Row in Google Sheets Writes six columns per qualified lead to the tracking sheet: Company Name, Category, Website, Phone Number, Email Address, and Address. All leads are logged before any email is sent, creating a pre-outreach record.
Stage 6: Loop and Pacing
Node 9 - Loop Over Items (splitInBatches)
Iterates over all logged leads one at a time. Configured with onError: continueRegularOutput so a failure on a single lead does not halt the remaining queue.
Node 10 - Wait Pauses briefly between each loop iteration to pace outreach and avoid triggering rate limits on the Gmail API.
Stage 7: Cold Email Generation
Node 11 - Information Extractor: Cold Email Writer (OpenAI GPT-4.1-mini) Receives three values per lead — Company Name, Business Category, and Email Style — and generates a complete cold email for the digital marketing agency. The prompt enforces: open with the company name, use "We" not "I", keep it concise, and close with a full signature block.
Two attributes are extracted:
Mail Subject— an attention-grabbing subject lineMail Body— the complete email body
Node 12 - OpenAI GPT-4.1-mini Chat Model
Powers the cold email generation node. Model is explicitly pinned to gpt-4.1-mini.
Stage 8: Dispatch and Status Writeback
Node 13 - Edit Fields: Timestamp Prep
Captures the send timestamp in MM-dd-yyyy (h:mm a) format and carries the lead's email address forward for both the Gmail send and the sheet update.
Node 14 - Gmail: Send Cold Email
Sends the generated email to the lead's address. Subject and body sourced directly from the Information Extractor output. Configured with maxTries: 2 and onError: continueRegularOutput — a send failure logs the error and moves to the next lead.
Node 15 - Append or Update Row in Google Sheets
Matches the lead's row by Email Address and writes two values: the send timestamp and a ✅ status indicator. After the write, execution returns to the Loop node for the next lead.
Results
- Zero manual steps between form submission and sent cold email — the full pipeline runs unattended
- Leads filtered at two stages: no-website records dropped at the Filter node, no-email records dropped at the validation node, keeping outreach focused on contactable businesses
- Per-lead audit trail in Google Sheets with send timestamp and status written back after each dispatch
- Personalized by tone and business type: each email is generated fresh using the lead's company name, category, and the operator-selected style — not a static template
- Loop-safe execution: a failure on any single lead does not stop the remaining queue
Stack
| Layer | Tool |
|---|---|
| Automation | n8n (self-hosted) |
| Trigger | n8n Form Trigger |
| Lead Scraping | Apify (Google Maps actor, HTTP Request) |
| Email Extraction | Google Gemini (LangChain Information Extractor) |
| Email Writing | OpenAI GPT-4.1-mini (LangChain Information Extractor) |
| Lead Logging | Google Sheets (append + appendOrUpdate) |
| Email Delivery | Gmail API |
My Role
- Designed the four-field form intake covering business type, location, lead volume, and email tone
- Configured the Apify HTTP Request with a full JSON body mapping all form fields to scraper parameters
- Built the two-stage filtering logic: website existence check at the Filter node,
@presence check at the If node - Wired Google Gemini as the language model for website-to-email extraction and OpenAI GPT-4.1-mini for cold email generation
- Structured the Google Sheets append node to write six lead columns before outreach, and the appendOrUpdate node to write send timestamp and status after each dispatch
- Implemented the Loop Over Items with
continueRegularOutputerror handling so individual lead failures do not abort the full run - Built the timestamp preparation node and configured Gmail with retry logic and error-tolerant execution