{
  "id": "gS5iqNgP6cxdagf6",
  "meta": {
    "builderVariant": "mcp",
    "aiBuilderAssisted": true
  },
  "name": "Find and verify business emails then draft AI icebreakers in Google Sheets",
  "tags": [],
  "nodes": [
    {
      "id": "02c42d42-7fc7-4d18-8bf3-6aadd35e78f9",
      "name": "Run email enrichment",
      "type": "n8n-nodes-base.manualTrigger",
      "position": [
        352,
        -288
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "8f72beff-8460-428e-9377-7469efeb2485",
      "name": "Configuration",
      "type": "n8n-nodes-base.set",
      "position": [
        528,
        -288
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "c1",
              "name": "scrapercity_finder_url",
              "type": "string",
              "value": "https://app.scrapercity.com/api/v1/email-finder"
            },
            {
              "id": "c2",
              "name": "scrapercity_status_url",
              "type": "string",
              "value": "https://app.scrapercity.com/api/v1/scrape/status/"
            },
            {
              "id": "c3",
              "name": "scrapercity_download_url",
              "type": "string",
              "value": "https://app.scrapercity.com/api/downloads/"
            },
            {
              "id": "c4",
              "name": "poll_wait_seconds",
              "type": "number",
              "value": 30
            },
            {
              "id": "c5",
              "name": "max_status_checks",
              "type": "number",
              "value": 20
            },
            {
              "id": "c6",
              "name": "ai_model",
              "type": "string",
              "value": "gpt-4o-mini"
            },
            {
              "id": "c7",
              "name": "icebreaker_language",
              "type": "string",
              "value": "English"
            },
            {
              "id": "c8",
              "name": "your_offer",
              "type": "string",
              "value": "AI automation that saves teams hours of manual work every week"
            },
            {
              "id": "c9",
              "name": "notify_email",
              "type": "string",
              "value": "you@example.com"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "5cec08cc-4b2a-4223-8ead-08cc408b2e4a",
      "name": "Get contacts from Sheet",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        784,
        -288
      ],
      "parameters": {
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultName": "contacts"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultName": "Select your input spreadsheet"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "57aea303-d10d-4ba3-b4ac-5bee94d0cc30",
      "name": "Build contacts payload",
      "type": "n8n-nodes-base.aggregate",
      "position": [
        1040,
        -288
      ],
      "parameters": {
        "include": "specifiedFields",
        "options": {},
        "aggregate": "aggregateAllItemData",
        "fieldsToInclude": "firstName, lastName, domain",
        "destinationFieldName": "contacts"
      },
      "typeVersion": 1
    },
    {
      "id": "9ac3d760-7d21-4fc1-9711-1fefa687b09b",
      "name": "Submit to ScraperCity",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1328,
        -288
      ],
      "parameters": {
        "url": "={{ $('Configuration').item.json.scrapercity_finder_url }}",
        "method": "POST",
        "options": {},
        "jsonBody": "={{ { \"contacts\": $json.contacts } }}",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth"
      },
      "typeVersion": 4.4
    },
    {
      "id": "6fb9f182-f659-4e4f-9f00-e96c9317443f",
      "name": "Wait before status check",
      "type": "n8n-nodes-base.wait",
      "position": [
        1536,
        -288
      ],
      "parameters": {
        "amount": "={{ $('Configuration').item.json.poll_wait_seconds }}"
      },
      "typeVersion": 1.1
    },
    {
      "id": "6ffe8942-59b6-44ee-9caa-8eed4987b069",
      "name": "Check job status",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1728,
        -288
      ],
      "parameters": {
        "url": "={{ $('Configuration').item.json.scrapercity_status_url }}{{ $('Submit to ScraperCity').item.json.runId }}",
        "options": {},
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth"
      },
      "typeVersion": 4.4
    },
    {
      "id": "3799a51a-f00f-436b-957b-65a8bb3f03e8",
      "name": "Route by job status",
      "type": "n8n-nodes-base.switch",
      "position": [
        1904,
        -304
      ],
      "parameters": {
        "rules": {
          "values": [
            {
              "outputKey": "completed",
              "conditions": {
                "options": {
                  "version": 1,
                  "leftValue": "",
                  "caseSensitive": false,
                  "typeValidation": "loose"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.status }}",
                    "rightValue": "SUCCEEDED"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "stopped",
              "conditions": {
                "options": {
                  "version": 1,
                  "leftValue": "",
                  "caseSensitive": false,
                  "typeValidation": "loose"
                },
                "combinator": "or",
                "conditions": [
                  {
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.status }}",
                    "rightValue": "FAILED"
                  },
                  {
                    "operator": {
                      "type": "number",
                      "operation": "gte"
                    },
                    "leftValue": "={{ $runIndex }}",
                    "rightValue": "={{ $('Configuration').item.json.max_status_checks }}"
                  }
                ]
              },
              "renameOutput": true
            }
          ]
        },
        "options": {
          "fallbackOutput": "extra",
          "renameFallbackOutput": "still processing"
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "a50d98f0-125e-4804-987c-29674cf58c63",
      "name": "Download results",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2480,
        -320
      ],
      "parameters": {
        "url": "={{ $('Configuration').item.json.scrapercity_download_url }}{{ $('Submit to ScraperCity').item.json.runId }}",
        "options": {
          "response": {
            "response": {
              "responseFormat": "file"
            }
          }
        },
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth"
      },
      "typeVersion": 4.4
    },
    {
      "id": "7b0e656f-5c0b-4f7b-85dd-e3900e4fdb17",
      "name": "Extract results from CSV",
      "type": "n8n-nodes-base.extractFromFile",
      "position": [
        2672,
        -320
      ],
      "parameters": {
        "options": {
          "headerRow": true
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "a5e8fcc1-1af7-4c40-893a-eada476a3019",
      "name": "Normalize result fields",
      "type": "n8n-nodes-base.code",
      "notes": "Code node used to map ScraperCity CSV headers onto a stable schema so downstream nodes are deterministic.",
      "position": [
        2896,
        -320
      ],
      "parameters": {
        "jsCode": "const pick = (obj, keys) => {\n  for (const k of Object.keys(obj)) {\n    if (keys.includes(String(k).toLowerCase().trim())) return obj[k];\n  }\n  return '';\n};\nreturn $input.all().map(({ json }) => ({\n  json: {\n    firstName: pick(json, ['firstname','first_name','first name','first']),\n    lastName: pick(json, ['lastname','last_name','last name','last']),\n    domain: pick(json, ['domain','company_domain','company domain','website']),\n    email: pick(json, ['email','email_address','work_email','business_email']),\n    status: pick(json, ['status','verification_status','verification','deliverability','state']),\n    provider: pick(json, ['provider','mail_provider','email_provider','esp']),\n  }\n}));"
      },
      "typeVersion": 2
    },
    {
      "id": "84ba0631-2b1b-448a-b3eb-a7d96eb2c868",
      "name": "Keep verified emails",
      "type": "n8n-nodes-base.filter",
      "position": [
        3072,
        -320
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 1,
            "leftValue": "",
            "caseSensitive": false,
            "typeValidation": "loose"
          },
          "combinator": "and",
          "conditions": [
            {
              "operator": {
                "type": "string",
                "operation": "notEmpty",
                "singleValue": true
              },
              "leftValue": "={{ $json.email }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "05f01dd9-08bf-4ebd-bef7-6b5f3fce870f",
      "name": "Generate AI icebreaker",
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "position": [
        2336,
        208
      ],
      "parameters": {
        "text": "=You write short, personalized cold-email opening lines for B2B outreach.\nWrite ONE opening line (max 30 words), in {{ $('Configuration').item.json.icebreaker_language }}, for this prospect:\n- Name: {{ $('Keep verified emails').item.json.firstName }} {{ $('Keep verified emails').item.json.lastName }}\n- Company domain: {{ $('Keep verified emails').item.json.domain }}\nWhat I offer: {{ $('Configuration').item.json.your_offer }}\nRules: sound human and specific, reference their company, no greeting, no emojis. Output only the sentence.",
        "batching": {},
        "promptType": "define"
      },
      "typeVersion": 1.9
    },
    {
      "id": "66e41ae6-b996-466a-806a-0a361cf5e1ff",
      "name": "OpenAI Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        2336,
        368
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Configuration').item.json.ai_model }}"
        },
        "options": {},
        "builtInTools": {}
      },
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "6fa4c708-bbee-4be4-bd18-e36c2d6dee03",
      "name": "Save enriched leads to Sheet",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        2656,
        224
      ],
      "parameters": {
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultName": "leads"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultName": "Select your output spreadsheet"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "943f5b79-6041-480f-8a7c-6f3be5fb2b80",
      "name": "Send run summary email",
      "type": "n8n-nodes-base.gmail",
      "position": [
        2864,
        224
      ],
      "parameters": {
        "sendTo": "={{ $('Configuration').item.json.notify_email }}",
        "message": "=Your ScraperCity email enrichment run finished.\n\nContacts submitted: {{ $('Build contacts payload').item.json.contacts.length }}\nVerified emails found: {{ $('Keep verified emails').all().length }}\n\nThe enriched leads (email + verification status + AI icebreaker) were written to your Google Sheet.",
        "options": {},
        "subject": "=Email enrichment done - {{ $('Keep verified emails').all().length }} verified leads",
        "emailType": "text"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "executeOnce": true,
      "typeVersion": 2.2
    },
    {
      "id": "4253b1ad-d575-45cd-b73c-891d3b9964ef",
      "name": "Stop - job failed or timed out",
      "type": "n8n-nodes-base.noOp",
      "position": [
        2192,
        -288
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "d70325ee-0bec-4d93-b22e-490422bd57ca",
      "name": "Sticky Note 1d8f3145",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -320,
        -528
      ],
      "parameters": {
        "color": 4,
        "width": 640,
        "height": 1528,
        "content": "# Find and verify business emails then draft AI icebreakers in Google Sheets\n# [Open full documentation on Notion](https://automatisation.notion.site/Course-Find-and-verify-business-emails-then-draft-AI-icebreakers-in-Google-Sheets-39d3d6550fd9810b8200d55f10e2a1c5)\n\n## How it works\nReads contacts (first name, last name, company domain) from Google Sheets, sends them to the ScraperCity Email Finder API, polls until done, keeps only verified emails, drafts a personalized opening line per contact with OpenAI, writes everything back to Sheets and emails a summary.\n\n## Setup\n1. Create a ScraperCity account and copy your API key.\n2. Create an HTTP Header Auth credential named ScraperCity API Key (Name Authorization, Value Bearer YOUR_KEY) and select it on the 3 ScraperCity HTTP nodes.\n3. Set your values in Configuration.\n4. Pick input and output spreadsheets.\n\n## Requirements\n- ScraperCity account with Email Finder credits\n- OpenAI credential (OpenAi account)\n- Google Sheets + Gmail credentials\n- Input columns: firstName, lastName, domain\n\n## Customization\n- Swap Manual Trigger for a Schedule Trigger.\n- Adjust poll_wait_seconds / max_status_checks.\n- Edit the icebreaker prompt.\n\nNeed help customizing?\nContact me for consulting and support : [Linkedin](https://www.linkedin.com/in/doctor-firass/)\n\n# MY NEW YOUTUBE CHANNEL\n[Subscribe to my new YouTube channel](https://www.youtube.com/@DrFiras_AI).\n\n[![The AI Doctor](https://www.dr-firas.com/the-ai-doctor.png)](https://www.youtube.com/@DrFiras_AI)"
      },
      "typeVersion": 1
    },
    {
      "id": "cd65b7bc-47c2-41e1-b3fe-8cbd052cfca2",
      "name": "Sticky Note 8c780143",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        704,
        -480
      ],
      "parameters": {
        "color": 7,
        "width": 480,
        "height": 360,
        "content": "## 1. Input & configuration\nAll adjustable settings live in Configuration. Contacts are read from your Google Sheet."
      },
      "typeVersion": 1
    },
    {
      "id": "64d22967-7bdd-46d6-92bb-b197bc63766d",
      "name": "Sticky Note 816d1cf9",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1232,
        -592
      ],
      "parameters": {
        "color": 7,
        "width": 920,
        "height": 520,
        "content": "## 2. Find emails with ScraperCity\nSubmit contacts, poll status until SUCCEEDED (or stop on FAILED / timeout)."
      },
      "typeVersion": 1
    },
    {
      "id": "a142b4a6-c6f6-4793-95ce-3d0b8c65b282",
      "name": "Sticky Note 31d256a6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2336,
        -576
      ],
      "parameters": {
        "color": 7,
        "width": 900,
        "height": 500,
        "content": "## 3. Clean & filter\nDownload the CSV, normalize columns, keep only verified emails."
      },
      "typeVersion": 1
    },
    {
      "id": "dcb4ae04-22dd-4da4-8f9f-95dc19810995",
      "name": "Sticky Note 23c083aa",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2320,
        48
      ],
      "parameters": {
        "color": 7,
        "width": 260,
        "height": 500,
        "content": "## 4. AI personalization\nOne personalized opening line per verified contact."
      },
      "typeVersion": 1
    },
    {
      "id": "26a99151-5ac7-43e1-973e-36291cf1b41f",
      "name": "Sticky Note 035a826e",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2608,
        48
      ],
      "parameters": {
        "color": 7,
        "width": 480,
        "height": 500,
        "content": "## 5. Save & notify\nWrite enriched leads to Sheets and email a run summary."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "availableInMCP": true,
    "executionOrder": "v1"
  },
  "versionId": "aabf972b-b4f1-4077-9b8d-3104e45e361a",
  "nodeGroups": [],
  "connections": {
    "Configuration": {
      "main": [
        [
          {
            "node": "Get contacts from Sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check job status": {
      "main": [
        [
          {
            "node": "Route by job status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Download results": {
      "main": [
        [
          {
            "node": "Extract results from CSV",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "Generate AI icebreaker",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Route by job status": {
      "main": [
        [
          {
            "node": "Download results",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Stop - job failed or timed out",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Wait before status check",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Keep verified emails": {
      "main": [
        [
          {
            "node": "Generate AI icebreaker",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Run email enrichment": {
      "main": [
        [
          {
            "node": "Configuration",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Submit to ScraperCity": {
      "main": [
        [
          {
            "node": "Wait before status check",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build contacts payload": {
      "main": [
        [
          {
            "node": "Submit to ScraperCity",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate AI icebreaker": {
      "main": [
        [
          {
            "node": "Save enriched leads to Sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get contacts from Sheet": {
      "main": [
        [
          {
            "node": "Build contacts payload",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Normalize result fields": {
      "main": [
        [
          {
            "node": "Keep verified emails",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract results from CSV": {
      "main": [
        [
          {
            "node": "Normalize result fields",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait before status check": {
      "main": [
        [
          {
            "node": "Check job status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Save enriched leads to Sheet": {
      "main": [
        [
          {
            "node": "Send run summary email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}