AutomationFlowsAI & RAG › Send Daily Ai-personalized Cold Emails with Google Places and Openai

Send Daily Ai-personalized Cold Emails with Google Places and Openai

ByHarvey Kubath @agenticbuilds on n8n.io

This workflow runs every morning to find local businesses via Google Places, pulls their website content to extract an email address, uses OpenAI to draft a personalised automation-focused outreach message, then sends it via SMTP while tracking contacts in an n8n Data Table.…

Cron / scheduled trigger★★★★☆ complexityAI-powered27 nodesHTTP RequestData TableAgentOpenAI ChatOutput Parser StructuredEmail Send
AI & RAG Trigger: Cron / scheduled Nodes: 27 Complexity: ★★★★☆ AI nodes: yes Added:

This workflow corresponds to n8n.io template #16940 — we link there as the canonical source.

This workflow follows the Agent → Datatable recipe pattern — see all workflows that pair these two integrations.

The workflow JSON

Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →

Download .json
{
  "id": "rF6kPr3IYBbVEeIZ",
  "meta": {
    "builderVariant": "mcp",
    "aiBuilderAssisted": true
  },
  "name": "AI Cold Outreach Agent (Template)",
  "tags": [],
  "nodes": [
    {
      "id": "7b015635-88ca-4ddf-afb5-cdbb9086937b",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -48,
        -800
      ],
      "parameters": {
        "width": 480,
        "height": 880,
        "content": "## AI Cold Outreach Agent (Template)\n\n### How it works\n\nThis workflow runs on a daily schedule to find businesses in a configured niche and location, extract contact emails from their websites, and send personalised cold outreach emails. It filters out leads without websites or valid emails, skips businesses already contacted, caps the number of sends per day, and uses an AI agent to draft each message. After each email is sent, it logs the contact and pauses before continuing through the send loop until the campaign is complete.\n\n### Setup steps\n\n- Configure the Campaign Config node with the target niche, location, sender name, and sender company.\n- Add Google Places API credentials or an API key to the Google Places HTTP request node.\n- Configure the OpenAI credentials/model used by the AI Agent sub-node.\n- Set up the email sending credentials in the Send Cold Email node, such as SMTP or the selected email provider.\n- Create or connect the n8n data table used to check previously contacted leads and log new contacts.\n- Review the daily schedule, daily send cap, and pause duration to match outreach limits and compliance requirements.\n\n### Customization\n\nAdjust the niche, location, prompt instructions, structured email output schema, daily send limit, and wait time between sends to fit different campaigns or outreach styles."
      },
      "typeVersion": 1
    },
    {
      "id": "fbec120c-aba3-43a6-ab44-0f0dc765926e",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        512,
        -464
      ],
      "parameters": {
        "color": 7,
        "width": 432,
        "height": 320,
        "content": "## Schedule campaign setup\n\nStarts the workflow on a daily schedule and defines the campaign parameters used to search for prospects and personalise outreach."
      },
      "typeVersion": 1
    },
    {
      "id": "f86ddcac-9efa-455f-9c14-e0d72f1a969b",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1008,
        -464
      ],
      "parameters": {
        "color": 7,
        "width": 640,
        "height": 320,
        "content": "## Find and normalize leads\n\nSearches Google Places for matching businesses, splits the returned list into individual items, and standardizes each lead with business name, website, and address fields."
      },
      "typeVersion": 1
    },
    {
      "id": "4bf9bd9f-e65e-49cb-82e1-bca5615b8a2c",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1680,
        -432
      ],
      "parameters": {
        "color": 7,
        "width": 864,
        "height": 304,
        "content": "## Extract valid emails\n\nKeeps only leads with websites, fetches each website, extracts an email address from the page content, and filters out leads without a valid email."
      },
      "typeVersion": 1
    },
    {
      "id": "edb2156d-c3a3-4c49-afc1-679e4bf9da64",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2576,
        -464
      ],
      "parameters": {
        "color": 7,
        "width": 592,
        "height": 320,
        "content": "## Deduplicate and batch sends\n\nChecks the contact log to avoid emailing previously contacted businesses, limits the number of leads processed per day, and feeds the remaining leads into a batch loop."
      },
      "typeVersion": 1
    },
    {
      "id": "d1d66709-bba1-4e0e-a028-51209eadda05",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3216,
        -464
      ],
      "parameters": {
        "color": 7,
        "width": 640,
        "height": 480,
        "content": "## Generate email content\n\nUses an AI agent with an OpenAI chat model and structured output parser to write a personalised email, then maps the generated content into subject and body fields ready for sending."
      },
      "typeVersion": 1
    },
    {
      "id": "adaa7c70-e69e-4765-8161-7b2e02f02d72",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3888,
        -624
      ],
      "parameters": {
        "color": 7,
        "width": 640,
        "height": 592,
        "content": "## Send log and finish\n\nSends the cold email, records the contacted lead, pauses before looping to the next batch item, and marks the campaign complete when the send loop has no more items."
      },
      "typeVersion": 1
    },
    {
      "id": "f0bd3f85-4d08-4e9f-8013-d95e975c8401",
      "name": "Every Morning at 9am",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        560,
        -304
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "triggerAtHour": 9
            }
          ]
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "03a97114-1433-4ee1-93d0-1f85784b3f7e",
      "name": "Set Campaign Parameters",
      "type": "n8n-nodes-base.set",
      "position": [
        800,
        -304
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "c1",
              "name": "niche",
              "type": "string",
              "value": "={{ [\"Cleaners\",\"Plumbers\",\"Electricians\",\"Landscapers\",\"Painters and Decorators\",\"Hairdressers\",\"Barbers\",\"Beauty Salons\",\"Dentists\",\"Physiotherapists\",\"Restaurants\",\"Cafes\",\"Gyms\",\"Car Garages\",\"Estate Agents\",\"Accountants\",\"Solicitors\",\"Vets\",\"Driving Schools\",\"Photographers\"][($now.ordinal - 1) % 20] }}"
            },
            {
              "id": "c2",
              "name": "location",
              "type": "string",
              "value": "={{ [\"Dublin\",\"Cork\",\"Galway\",\"Limerick\",\"Waterford\"][($now.ordinal - 1) % 5] }}"
            },
            {
              "id": "c3",
              "name": "senderName",
              "type": "string",
              "value": "Your Name"
            },
            {
              "id": "c4",
              "name": "senderCompany",
              "type": "string",
              "value": "Your Company"
            },
            {
              "id": "c5",
              "name": "companyType",
              "type": "string",
              "value": "an automation agency"
            },
            {
              "id": "c6",
              "name": "senderEmail",
              "type": "string",
              "value": "user@example.com"
            },
            {
              "id": "c7",
              "name": "senderAddress",
              "type": "string",
              "value": "Your Street, Your City, Your Country"
            },
            {
              "id": "c8",
              "name": "senderCity",
              "type": "string",
              "value": "Your City"
            },
            {
              "id": "c9",
              "name": "serviceArea",
              "type": "string",
              "value": "Your Country"
            },
            {
              "id": "c10",
              "name": "websiteUrl",
              "type": "string",
              "value": "https://yourdomain.com"
            },
            {
              "id": "c11",
              "name": "websiteLabel",
              "type": "string",
              "value": "yourdomain.com"
            },
            {
              "id": "c12",
              "name": "dailyCap",
              "type": "number",
              "value": 16
            },
            {
              "id": "c13",
              "name": "sendDelaySeconds",
              "type": "number",
              "value": 60
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "b7543874-b848-4911-b8eb-a2f0c4aabd65",
      "name": "Search Google Places for Businesses",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1056,
        -304
      ],
      "parameters": {
        "url": "https://places.googleapis.com/v1/places:searchText",
        "method": "POST",
        "options": {},
        "jsonBody": "={ \"textQuery\": \"{{ $json.niche }} in {{ $json.location }}\", \"pageSize\": 20 }",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "headerParameters": {
          "parameters": [
            {
              "name": "X-Goog-FieldMask",
              "value": "places.displayName,places.websiteUri,places.formattedAddress,places.nationalPhoneNumber"
            }
          ]
        }
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "13256f83-2183-482d-9d31-a0430cd90d0f",
      "name": "Split Business Results",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        1280,
        -304
      ],
      "parameters": {
        "options": {},
        "fieldToSplitOut": "places"
      },
      "typeVersion": 1
    },
    {
      "id": "54176a42-8b0f-4779-b9f9-133952c56d3e",
      "name": "Prepare Lead Information",
      "type": "n8n-nodes-base.set",
      "position": [
        1504,
        -304
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "n1",
              "name": "businessName",
              "type": "string",
              "value": "={{ $json.displayName.text }}"
            },
            {
              "id": "n2",
              "name": "website",
              "type": "string",
              "value": "={{ $json.websiteUri }}"
            },
            {
              "id": "n3",
              "name": "address",
              "type": "string",
              "value": "={{ $json.formattedAddress }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "392026dc-390f-4df9-8905-a62de5fb2942",
      "name": "Filter Businesses with Website",
      "type": "n8n-nodes-base.filter",
      "position": [
        1728,
        -304
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "w1",
              "operator": {
                "type": "string",
                "operation": "notEmpty"
              },
              "leftValue": "={{ $json.website }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "d782c557-a29c-4576-ae46-ee290679d2a5",
      "name": "Fetch Business Website",
      "type": "n8n-nodes-base.httpRequest",
      "onError": "continueRegularOutput",
      "position": [
        1952,
        -304
      ],
      "parameters": {
        "url": "={{ $json.website }}",
        "options": {
          "timeout": 15000,
          "response": {
            "response": {
              "neverError": true,
              "responseFormat": "text"
            }
          }
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "dd28becf-6729-4b84-b0c8-46c1ee6dd091",
      "name": "Extract Email from Website",
      "type": "n8n-nodes-base.code",
      "position": [
        2176,
        -304
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "const html = ($input.item.json.data || $input.item.json.body || \"\") + \"\";\nconst lead = $('Prepare Lead Information').item.json;\nconst matches = html.match(/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}/g) || [];\nconst bad = [\".png\",\".jpg\",\".jpeg\",\".gif\",\".webp\",\".svg\",\"sentry\",\"wixpress\",\"example.\",\"godaddy\",\"@2x\"];\nconst clean = matches.filter(e => !bad.some(b => e.toLowerCase().includes(b)));\nconst pref = [\"info@\",\"hello@\",\"contact@\",\"enquiries@\",\"enquiry@\",\"sales@\",\"hi@\",\"admin@\",\"office@\"];\nlet email = clean.find(e => pref.some(p => e.toLowerCase().startsWith(p))) || clean[0] || \"\";\nemail = email.toLowerCase();\nconst text = html.replace(/<script[\\s\\S]*?<\\/script>/gi,\" \").replace(/<style[\\s\\S]*?<\\/style>/gi,\" \").replace(/<[^>]+>/g,\" \").replace(/\\s+/g,\" \").trim().slice(0, 600);\nreturn { json: { businessName: lead.businessName, website: lead.website, address: lead.address, email, siteSnippet: text } };"
      },
      "typeVersion": 2
    },
    {
      "id": "106d5d65-6909-4c39-a9d3-f84bb10f61a2",
      "name": "Filter Valid Emails",
      "type": "n8n-nodes-base.filter",
      "position": [
        2400,
        -304
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 1,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "loose"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "v1",
              "operator": {
                "type": "string",
                "operation": "notEmpty"
              },
              "leftValue": "={{ $json.email }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "0ea0b93c-7db5-4f44-8a86-6971b6b603fe",
      "name": "Filter Contacted Leads",
      "type": "n8n-nodes-base.dataTable",
      "position": [
        2624,
        -304
      ],
      "parameters": {
        "filters": {
          "conditions": [
            {
              "keyName": "email",
              "keyValue": "={{ $json.email }}"
            }
          ]
        },
        "operation": "rowNotExists",
        "dataTableId": {
          "__rl": true,
          "mode": "name",
          "value": "outreach_contacts"
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "b3d5aa1a-95a1-41a0-a747-91bb2494574e",
      "name": "Limit Daily Email Sends",
      "type": "n8n-nodes-base.limit",
      "position": [
        2848,
        -304
      ],
      "parameters": {
        "maxItems": "={{ $('Set Campaign Parameters').item.json.dailyCap }}"
      },
      "typeVersion": 1
    },
    {
      "id": "25f653b2-6440-4c3a-853a-ac9a352bc5e2",
      "name": "Set Campaign Completion Status",
      "type": "n8n-nodes-base.set",
      "position": [
        4160,
        -464
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "cc1",
              "name": "status",
              "type": "string",
              "value": "Campaign run complete"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "09dff468-a406-4cd2-8d7c-7c5761968cf8",
      "name": "AI Email Writer Agent",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        3312,
        -304
      ],
      "parameters": {
        "text": "=You are writing a warm, consultative B2B cold outreach email for {{ $('Set Campaign Parameters').item.json.senderName }} of {{ $('Set Campaign Parameters').item.json.senderCompany }}, {{ $('Set Campaign Parameters').item.json.companyType }} that helps small businesses in {{ $('Set Campaign Parameters').item.json.serviceArea }} save time and money with practical AI and workflow automation.\n\nIMPORTANT: This email is strictly about AI and automation services only. Never offer, mention, or imply building, designing, redesigning, hosting, or improving their website - that is not what we do. The website details below are only background research to personalise the email.\n\nTarget business: {{ $json.businessName }}\nWhat they do (from their website): {{ $json.siteSnippet }}\n\nWrite a genuine, easy-to-read email of roughly 120 to 170 words. Lay it out so it is tidy and easy to scan, with short paragraphs and a blank line between each section, in this exact structure:\n\n1. A short, friendly greeting and a one-sentence introduction: the sender's first name (the first name from {{ $('Set Campaign Parameters').item.json.senderName }}), that they own {{ $('Set Campaign Parameters').item.json.senderCompany }}, {{ $('Set Campaign Parameters').item.json.companyType }} based in {{ $('Set Campaign Parameters').item.json.senderCity }}. Keep it natural, for example: \"Hi there, my name is Sam and I own Acme Automations, an automation agency based in Dublin.\"\n\n2. One short sentence making a specific, genuine observation about what this business does (drawn from the details above), so it is clear the sender actually understands their business.\n\n3. One short lead-in line ending in a colon (for example: \"A few automations that could help a business like yours:\"), then a bulleted list of 2 to 3 ideas. Put each idea on its OWN new line, starting with the bullet character \"\u2022 \". Keep each bullet to a single short line of about 6 to 12 words, naming the automation and the time, money, or hassle it saves. Do NOT write these ideas as one long sentence or paragraph. Choose the ideas most relevant to THIS business from areas like: instantly replying to missed calls and online enquiries, online booking with automatic reminders, fast quotes, review requests, lead follow-up, staff scheduling and rostering, invoicing and chasing late payments, supplier or stock ordering, job and time tracking, and automatic reporting.\n\n4. One short closing line with a single low-friction question asking if they are open to a quick chat.\n\nFormatting rules:\n- Separate every section with a blank line so the email breathes and is easy on the eye.\n- The automation ideas MUST be a vertical bulleted list, each on its own line beginning with \"\u2022 \" - never a run-on sentence.\n- Keep bullets concise: short phrases, not full sentences.\n\nSound human, helpful and grounded - a knowledgeable local peer sharing automation ideas, never salesy, hyped or generic. Do not invent facts you cannot reasonably infer from the website snippet. Keep the entire email focused on automation - do not pitch web design or any other service. Avoid the words revolutionary, cutting-edge, and game-changer. Do not include a sign-off, signature or unsubscribe line; those are added automatically. Return a subject line and the body text, keeping the line breaks and bullets exactly as described.",
        "options": {},
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 3.1
    },
    {
      "id": "025470b7-7c39-41e3-a365-f84ad8f42539",
      "name": "OpenAI GPT-5 Mini Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        3296,
        -128
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-5-mini",
          "cachedResultName": "gpt-5-mini"
        },
        "options": {},
        "builtInTools": {}
      },
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "77e108a4-7d99-4362-ac67-5b277c4563f7",
      "name": "Parse Email Output",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [
        3552,
        -112
      ],
      "parameters": {
        "jsonSchemaExample": "{ \"subject\": \"A short subject line\", \"body\": \"The full email body as plain text with line breaks\" }"
      },
      "typeVersion": 1.3
    },
    {
      "id": "23901065-6685-4343-9ed1-178c8d9bc6b7",
      "name": "Build Email Content",
      "type": "n8n-nodes-base.set",
      "position": [
        3712,
        -304
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "p1",
              "name": "subject",
              "type": "string",
              "value": "={{ $json.output?.subject ?? $json.subject ?? \"Quick idea for your business\" }}"
            },
            {
              "id": "p2",
              "name": "bodyText",
              "type": "string",
              "value": "={{ $json.output?.body ?? $json.body ?? \"\" }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "bffc3d43-214c-4cca-8ed8-bc1f2c49a0e4",
      "name": "Send Personalized Cold Email",
      "type": "n8n-nodes-base.emailSend",
      "onError": "continueRegularOutput",
      "position": [
        3936,
        -304
      ],
      "parameters": {
        "html": "={{ $json.bodyText.replaceAll(\"\\n\", \"<br>\") }}<br><br>\u2014<br>{{ $('Set Campaign Parameters').item.json.senderName }}<br>{{ $('Set Campaign Parameters').item.json.senderCompany }}<br><a href=\"{{ $('Set Campaign Parameters').item.json.websiteUrl }}\">{{ $('Set Campaign Parameters').item.json.websiteLabel }}</a><br>{{ $('Set Campaign Parameters').item.json.senderEmail }}<br>{{ $('Set Campaign Parameters').item.json.senderAddress }}<br><br><span style=\"color:#888;font-size:12px\">You are receiving this one-off email because your business is publicly listed in {{ $('Set Campaign Parameters').item.json.location }}. If you would prefer not to hear from me again, <a href=\"mailto:{{ $('Set Campaign Parameters').item.json.senderEmail }}?subject=Unsubscribe\">click here to unsubscribe</a> and you will be removed immediately.</span>",
        "options": {
          "replyTo": "={{ $('Set Campaign Parameters').item.json.senderEmail }}",
          "appendAttribution": false
        },
        "subject": "={{ $json.subject }}",
        "toEmail": "={{ $('Loop Through Email Batches').item.json.email }}",
        "fromEmail": "={{ $('Set Campaign Parameters').item.json.senderName }} <{{ $('Set Campaign Parameters').item.json.senderEmail }}>"
      },
      "credentials": {
        "smtp": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "9ace95d2-dd64-4508-8b3e-2d393ac8938e",
      "name": "Log Email Contact",
      "type": "n8n-nodes-base.dataTable",
      "position": [
        4160,
        -304
      ],
      "parameters": {
        "columns": {
          "value": {
            "email": "={{ $('Loop Through Email Batches').item.json.email }}",
            "status": "sent",
            "timestamp": "={{ $now.toISO() }}",
            "businessName": "={{ $('Loop Through Email Batches').item.json.businessName }}"
          },
          "schema": [
            {
              "id": "email",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "email",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "businessName",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "businessName",
              "defaultMatch": false,
              "canBeUsedToMatch": false
            },
            {
              "id": "status",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "status",
              "defaultMatch": false,
              "canBeUsedToMatch": false
            },
            {
              "id": "timestamp",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "timestamp",
              "defaultMatch": false,
              "canBeUsedToMatch": false
            }
          ],
          "mappingMode": "defineBelow"
        },
        "options": {},
        "dataTableId": {
          "__rl": true,
          "mode": "name",
          "value": "outreach_contacts"
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "194dbdd6-1255-4e4c-92bb-0dd566ecd925",
      "name": "Wait Between Email Sends",
      "type": "n8n-nodes-base.wait",
      "position": [
        4384,
        -160
      ],
      "parameters": {
        "amount": "={{ $('Set Campaign Parameters').item.json.sendDelaySeconds }}"
      },
      "typeVersion": 1.1
    },
    {
      "id": "52d9e4d9-8bb3-47a5-93f8-c48b3b64013c",
      "name": "Loop Through Email Batches",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        3024,
        -304
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "availableInMCP": true,
    "executionOrder": "v1"
  },
  "versionId": "f78317a2-046d-44b1-8a43-11e5629f6712",
  "nodeGroups": [],
  "connections": {
    "Log Email Contact": {
      "main": [
        [
          {
            "node": "Wait Between Email Sends",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Email Output": {
      "ai_outputParser": [
        [
          {
            "node": "AI Email Writer Agent",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "Build Email Content": {
      "main": [
        [
          {
            "node": "Send Personalized Cold Email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter Valid Emails": {
      "main": [
        [
          {
            "node": "Filter Contacted Leads",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Every Morning at 9am": {
      "main": [
        [
          {
            "node": "Set Campaign Parameters",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI Email Writer Agent": {
      "main": [
        [
          {
            "node": "Build Email Content",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Business Website": {
      "main": [
        [
          {
            "node": "Extract Email from Website",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter Contacted Leads": {
      "main": [
        [
          {
            "node": "Limit Daily Email Sends",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split Business Results": {
      "main": [
        [
          {
            "node": "Prepare Lead Information",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Limit Daily Email Sends": {
      "main": [
        [
          {
            "node": "Loop Through Email Batches",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI GPT-5 Mini Model": {
      "ai_languageModel": [
        [
          {
            "node": "AI Email Writer Agent",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Set Campaign Parameters": {
      "main": [
        [
          {
            "node": "Search Google Places for Businesses",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Lead Information": {
      "main": [
        [
          {
            "node": "Filter Businesses with Website",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait Between Email Sends": {
      "main": [
        [
          {
            "node": "Loop Through Email Batches",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Email from Website": {
      "main": [
        [
          {
            "node": "Filter Valid Emails",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop Through Email Batches": {
      "main": [
        [
          {
            "node": "Set Campaign Completion Status",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "AI Email Writer Agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Personalized Cold Email": {
      "main": [
        [
          {
            "node": "Log Email Contact",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter Businesses with Website": {
      "main": [
        [
          {
            "node": "Fetch Business Website",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Search Google Places for Businesses": {
      "main": [
        [
          {
            "node": "Split Business Results",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}

Credentials you'll need

Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

This workflow runs every morning to find local businesses via Google Places, pulls their website content to extract an email address, uses OpenAI to draft a personalised automation-focused outreach message, then sends it via SMTP while tracking contacts in an n8n Data Table.…

Source: https://n8n.io/workflows/16940/ — original creator credit. Request a take-down →

More AI & RAG workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

AI & RAG

This workflow automates performance governance and policy compliance monitoring for HR leaders, talent managers, and organizational development teams across enterprises. It solves the challenge of mai

HTTP Request, OpenAI Chat, Output Parser Structured +5
AI & RAG

This workflow automates policy compliance validation and approval orchestration through intelligent AI-driven assessment. Designed for compliance departments, legal teams, and governance officers, it

HTTP Request, OpenAI Chat, Output Parser Structured +4
AI & RAG

This workflow automates clinical trial signal validation and regulatory governance through intelligent AI-driven oversight. Designed for clinical research organizations, pharmaceutical companies, and

HTTP Request, OpenAI Chat, Output Parser Structured +3
AI & RAG

This workflow transforms natural language queries into research reports through a five-stage AI pipeline. When triggered via webhook (typically from Google Sheets using the companion [](https://gist.g

Redis, Agent, Output Parser Structured +7
AI & RAG

This workflow automates end-to-end sustainability lifecycle management for corporate sustainability teams, ESG governance officers, and circular economy programme leads. It addresses the challenge of

Form Trigger, Agent, OpenAI Chat +11