This workflow corresponds to n8n.io template #10827 β we link there as the canonical source.
This workflow follows the Agent β Gmail 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 β
{
"id": "ZXu9x8swL0SiSX6C",
"name": "AI-Powered Outreach & Follow-Up Automation (GPT-4o + Gmail + Google Sheets)",
"tags": [],
"nodes": [
{
"id": "0d069126-2ec1-43ac-8122-8d444f20c43b",
"name": "When clicking \u2018Execute workflow\u2019",
"type": "n8n-nodes-base.manualTrigger",
"position": [
-1232,
304
],
"parameters": {},
"typeVersion": 1
},
{
"id": "461208fc-76f3-4882-a743-ca623b2ca29b",
"name": "Configure GPT-4o Model",
"type": "@n8n/n8n-nodes-langchain.lmChatAzureOpenAi",
"position": [
-16,
832
],
"parameters": {
"model": "gpt-4o",
"options": {}
},
"credentials": {
"azureOpenAiApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "a7137b17-4d59-4ce1-857c-03e15e590f70",
"name": "Retrieve Lead Records from Google Sheets",
"type": "n8n-nodes-base.googleSheets",
"position": [
-944,
304
],
"parameters": {
"options": {},
"sheetName": {
"__rl": true,
"mode": "list",
"value": 46113423,
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/17rcNd_ZpUQLm0uWEVbD-NY6GyFUkrD4BglvawlyBygM/edit#gid=46113423",
"cachedResultName": "outreach automation"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "17rcNd_ZpUQLm0uWEVbD-NY6GyFUkrD4BglvawlyBygM",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/17rcNd_ZpUQLm0uWEVbD-NY6GyFUkrD4BglvawlyBygM/edit?usp=drivesdk",
"cachedResultName": "sample_leads_50"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4
},
{
"id": "35a5d947-361f-40a9-9d57-efe5a2d462db",
"name": "Validate Lead Data Payload",
"type": "n8n-nodes-base.if",
"position": [
-688,
304
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "e2adb005-2b3c-4d1e-8445-442df1fe925a",
"operator": {
"type": "string",
"operation": "notEmpty",
"singleValue": true
},
"leftValue": "=/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test({{ $json.Email }})",
"rightValue": ""
}
]
}
},
"typeVersion": 2.2
},
{
"id": "f7aaf899-8eec-4178-bc3e-88985592be72",
"name": "Filter for Booked Leads",
"type": "n8n-nodes-base.if",
"position": [
-400,
304
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "b7913fcd-b70c-47fd-a926-d09a0086b40e",
"operator": {
"name": "filter.operator.equals",
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json[\"Booking Status\"] }}",
"rightValue": "BOOKED"
}
]
}
},
"typeVersion": 2.2
},
{
"id": "35b45b6e-c542-49f7-aead-01c561647444",
"name": "Generate Personalized Outreach Email (AI)",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
0,
320
],
"parameters": {
"text": "=Generate a personalized outreach email in HTML format for this lead:\n\nCompany Name: {{ $json[\"Company Name\"] }}\nContact Person: {{ $json[\"Contact Person\"] }}\nJob Title: {{ $json[\"Job Title\"] }}\nIndustry: {{ $json[\"Industry\"] }}\nLocation: {{ $json[\"Location\"] }}\nLead Source: {{ $json[\"Lead Source\"] }}\nBooking Status: {{ $json[\"Booking Status\"] }}\n\nThe goal is to re-engage them and encourage a meeting booking.\nMention their company or industry naturally, and make it sound warm and specific.\nKeep it clean and mobile-friendly HTML (no styles or colors).\n",
"options": {
"systemMessage": "=You are an AI sales assistant that writes short, friendly, and professional B2B outreach emails in HTML format. \nEach email should be under 150 words and formatted using <p>, <b>, and <br> tags. \nAlways output both the Subject and the Email Body separately. \nDo not include <html> or <body> tags. \nThe tone should be polite, conversational, and slightly persuasive. \nEnd with a clear call to action (like booking a meeting) and sign off as \u201cSaurabh Garg, Sales Team.\u201d\nReturn your answer in JSON format with two keys:\n{\n \"subject\": \"...\",\n \"body_html\": \"...\"\n}\n"
},
"promptType": "define"
},
"typeVersion": 2.1
},
{
"id": "eb74688d-5d4b-4a8f-ba88-03111715fb52",
"name": "Parse AI Email Output (JavaScript)",
"type": "n8n-nodes-base.code",
"position": [
448,
320
],
"parameters": {
"jsCode": "// Loop through AI results and clean up JSON output\nreturn items.map(item => {\n let raw = item.json.output || '';\n \n // Remove code block markers like ```json or ```\n raw = raw.replace(/```json|```/g, '').trim();\n\n // Parse JSON safely\n let parsed;\n try {\n parsed = JSON.parse(raw);\n } catch (e) {\n parsed = { subject: \"No Subject\", body_html: \"Error parsing AI output.\" };\n }\n\n return { json: parsed };\n});\n"
},
"typeVersion": 2
},
{
"id": "5e6c825b-1739-411b-b7b5-291937596a9f",
"name": "Send Initial Outreach Email via Gmail",
"type": "n8n-nodes-base.gmail",
"position": [
768,
320
],
"parameters": {
"sendTo": "={{ $('Retrieve Lead Records from Google Sheets').item.json.Email }}",
"message": "={{ $json.body_html }}",
"options": {},
"subject": "={{ $json.subject }}"
},
"credentials": {
"gmailOAuth2": {
"name": "<your credential>"
}
},
"typeVersion": 2.1
},
{
"id": "540211f0-f006-4845-8fed-02d41d9fc634",
"name": "Wait Before Thread Check (24 hr)",
"type": "n8n-nodes-base.wait",
"position": [
1040,
320
],
"parameters": {
"amount": 24
},
"typeVersion": 1
},
{
"id": "537915a6-88d4-4353-b5f7-d0c2424119ce",
"name": "Fetch Sent Email Thread from Gmail",
"type": "n8n-nodes-base.gmail",
"position": [
1312,
320
],
"parameters": {
"options": {},
"resource": "thread",
"threadId": "={{ $('Send Initial Outreach Email via Gmail').item.json.threadId }}",
"operation": "get"
},
"credentials": {
"gmailOAuth2": {
"name": "<your credential>"
}
},
"typeVersion": 2.1
},
{
"id": "80bbd250-f9ab-46de-9ad6-b3ab8e7f3233",
"name": "Check for Client Reply (If Condition)",
"type": "n8n-nodes-base.if",
"position": [
1568,
320
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "4a6d1310-29be-4559-8bea-afe8fe0f0f30",
"operator": {
"type": "string",
"operation": "contains"
},
"leftValue": "={{$json[\"messages\"][1][\"snippet\"]}}",
"rightValue": "Yes"
}
]
}
},
"typeVersion": 2.2
},
{
"id": "5366521f-fc42-4907-9e1e-29994458578c",
"name": "Extract Reply Details (JavaScript)",
"type": "n8n-nodes-base.code",
"position": [
1920,
48
],
"parameters": {
"jsCode": "// Loop through all email threads where reply = true\nreturn items.map(item => {\n const data = item.json;\n\n // Extract the reply message (second email in thread)\n const reply = data.messages?.[1];\n const original = data.messages?.[0];\n\n // Clean the reply text (remove quoted text from Gmail)\n let clientMessage = reply?.snippet || \"\";\n clientMessage = clientMessage.split(\"On Wed\")[0].trim(); // basic cleanup example\n\n // Prepare clean structured output\n return {\n json: {\n Email: reply?.From?.match(/<(.+?)>/)?.[1] || reply?.From || \"\",\n ContactPerson: reply?.From?.split(\"<\")[0].trim() || \"\",\n ThreadID: reply?.threadId || data.id || \"\",\n Subject: reply?.Subject || original?.Subject || \"\",\n ClientMessage: clientMessage,\n BookingStatus: \"BOOKED\",\n LastUpdated: new Date().toISOString()\n }\n };\n});\n"
},
"typeVersion": 2
},
{
"id": "dfc24134-8604-47d3-8932-41df52d14620",
"name": "Update Lead Record \u2013 Booked (Google Sheets)",
"type": "n8n-nodes-base.googleSheets",
"position": [
2224,
48
],
"parameters": {
"columns": {
"value": {
"Email": "={{ $json.Email }}",
"ThreadID": "={{ $json.ThreadID }}",
"LastUpdated": "={{ $json.LastUpdated }}",
"ClientMessage": "={{ $json.ClientMessage }}",
"Booking Status": "={{ $json.BookingStatus }}"
},
"schema": [
{
"id": "Company Name",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Company Name",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Contact Person",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Contact Person",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Job Title",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Job Title",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Email",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Email",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Phone",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Phone",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Industry",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Industry",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Location",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Location",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Lead Source",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Lead Source",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Booking Status",
"type": "string",
"display": true,
"required": false,
"displayName": "Booking Status",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "ClientMessage",
"type": "string",
"display": true,
"required": false,
"displayName": "ClientMessage",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "LastUpdated",
"type": "string",
"display": true,
"required": false,
"displayName": "LastUpdated",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "ThreadID",
"type": "string",
"display": true,
"required": false,
"displayName": "ThreadID",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [
"Email"
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "appendOrUpdate",
"sheetName": {
"__rl": true,
"mode": "list",
"value": 46113423,
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/17rcNd_ZpUQLm0uWEVbD-NY6GyFUkrD4BglvawlyBygM/edit#gid=46113423",
"cachedResultName": "outreach automation"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "17rcNd_ZpUQLm0uWEVbD-NY6GyFUkrD4BglvawlyBygM",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/17rcNd_ZpUQLm0uWEVbD-NY6GyFUkrD4BglvawlyBygM/edit?usp=drivesdk",
"cachedResultName": "sample_leads_50"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.6
},
{
"id": "bf3a2ee4-1bbc-445e-8c3f-2119dd16e95d",
"name": "Wait Before Second Thread Check (24 hr)",
"type": "n8n-nodes-base.wait",
"position": [
2224,
544
],
"parameters": {
"unit": "seconds",
"amount": 24
},
"typeVersion": 1
},
{
"id": "6ac3e8ce-2dac-4953-97d2-3221e3d5be82",
"name": "Send Second Follow-Up Email via Gmail",
"type": "n8n-nodes-base.gmail",
"position": [
1888,
544
],
"parameters": {
"sendTo": "={{ $json.messages[0].To }}",
"message": "=<p>Hi {{ $json[\"Contact Person\"] || \"there\" }},</p>\n\n<p>I wanted to quickly follow up on my previous email. \nI understand things can get busy, so just checking if you had a chance to review my message.</p>\n\n<p>I\u2019d love to schedule a short chat to explore how we could support <b> {{ $('Retrieve Lead Records from Google Sheets').item.json['Contact Person'] }}</b> in your upcoming initiatives.</p>\n\n<p>If now\u2019s not a good time, no worries \u2014 just let me know when it might be better for you.</p>\n\n<p>Best regards,<br>\n<b>Saurabh Garg</b><br>\nSales Team</p>\n",
"options": {},
"subject": "Still open to a quick chat."
},
"credentials": {
"gmailOAuth2": {
"name": "<your credential>"
}
},
"typeVersion": 2.1
},
{
"id": "7b8c0b58-0aba-4b63-b690-6efee3c35d52",
"name": "Fetch Follow-Up Thread from Gmail",
"type": "n8n-nodes-base.gmail",
"position": [
2512,
544
],
"parameters": {
"options": {},
"resource": "thread",
"threadId": "={{ $json.threadId }}",
"operation": "get"
},
"credentials": {
"gmailOAuth2": {
"name": "<your credential>"
}
},
"typeVersion": 2.1
},
{
"id": "9b0df250-edcd-4963-a14d-7c332ca2ba78",
"name": "Check for Second Reply (If Condition)",
"type": "n8n-nodes-base.if",
"position": [
2784,
544
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "4a6d1310-29be-4559-8bea-afe8fe0f0f30",
"operator": {
"type": "string",
"operation": "contains"
},
"leftValue": "={{$json[\"messages\"][1][\"snippet\"]}}",
"rightValue": "Yes"
}
]
}
},
"typeVersion": 2.2
},
{
"id": "54350e4a-92e1-445e-aa9a-05ca7b2bc015",
"name": "Update Lead Status to Declined (Set Node)",
"type": "n8n-nodes-base.set",
"position": [
3200,
800
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "eddf188b-c756-4cd3-b5ac-3bdbce3a3049",
"name": "Booking Status",
"type": "string",
"value": "Declined"
},
{
"id": "df707470-60d7-4024-a998-8b7ba3c93283",
"name": "Email",
"type": "string",
"value": "={{ $json.messages[0].To }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "cb100856-ab8b-42d8-a899-8273a21d2498",
"name": "Update Lead Record \u2013 Declined (Google Sheets)",
"type": "n8n-nodes-base.googleSheets",
"position": [
3424,
800
],
"parameters": {
"columns": {
"value": {
"Email": "={{ $json.Email }}",
"Booking Status": "={{ $json[\"Booking Status\"] }}"
},
"schema": [
{
"id": "Company Name",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Company Name",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Contact Person",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Contact Person",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Job Title",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Job Title",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Email",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Email",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Phone",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Phone",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Industry",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Industry",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Location",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Location",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Lead Source",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Lead Source",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Booking Status",
"type": "string",
"display": true,
"required": false,
"displayName": "Booking Status",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "ClientMessage",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "ClientMessage",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "LastUpdated",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "LastUpdated",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "ThreadID",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "ThreadID",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [
"Email"
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "appendOrUpdate",
"sheetName": {
"__rl": true,
"mode": "list",
"value": 46113423,
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/17rcNd_ZpUQLm0uWEVbD-NY6GyFUkrD4BglvawlyBygM/edit#gid=46113423",
"cachedResultName": "outreach automation"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "17rcNd_ZpUQLm0uWEVbD-NY6GyFUkrD4BglvawlyBygM",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/17rcNd_ZpUQLm0uWEVbD-NY6GyFUkrD4BglvawlyBygM/edit?usp=drivesdk",
"cachedResultName": "sample_leads_50"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.6
},
{
"id": "392fd316-f1e0-4de5-aea6-5fb872b1c767",
"name": "Update Lead Record \u2013 Replied (Google Sheets)",
"type": "n8n-nodes-base.googleSheets",
"position": [
3440,
240
],
"parameters": {
"columns": {
"value": {
"Email": "={{ $json.Email }}",
"ThreadID": "={{ $json.ThreadID }}",
"LastUpdated": "={{ $json.LastUpdated }}",
"ClientMessage": "={{ $json.ClientMessage }}",
"Booking Status": "={{ $json.BookingStatus }}"
},
"schema": [
{
"id": "Company Name",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Company Name",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Contact Person",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Contact Person",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Job Title",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Job Title",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Email",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Email",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Phone",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Phone",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Industry",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Industry",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Location",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Location",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Lead Source",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Lead Source",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Booking Status",
"type": "string",
"display": true,
"required": false,
"displayName": "Booking Status",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "ClientMessage",
"type": "string",
"display": true,
"required": false,
"displayName": "ClientMessage",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "LastUpdated",
"type": "string",
"display": true,
"required": false,
"displayName": "LastUpdated",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "ThreadID",
"type": "string",
"display": true,
"required": false,
"displayName": "ThreadID",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [
"Email"
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "appendOrUpdate",
"sheetName": {
"__rl": true,
"mode": "list",
"value": 46113423,
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/17rcNd_ZpUQLm0uWEVbD-NY6GyFUkrD4BglvawlyBygM/edit#gid=46113423",
"cachedResultName": "outreach automation"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "17rcNd_ZpUQLm0uWEVbD-NY6GyFUkrD4BglvawlyBygM",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/17rcNd_ZpUQLm0uWEVbD-NY6GyFUkrD4BglvawlyBygM/edit?usp=drivesdk",
"cachedResultName": "sample_leads_50"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.6
},
{
"id": "6da18860-30f8-476a-84fc-b10084fc6f4e",
"name": "Extract Second Reply Details (JavaScript)",
"type": "n8n-nodes-base.code",
"position": [
3168,
240
],
"parameters": {
"jsCode": "// Loop through all email threads where reply = true\nreturn items.map(item => {\n const data = item.json;\n\n // Extract the reply message (second email in thread)\n const reply = data.messages?.[1];\n const original = data.messages?.[0];\n\n // Clean the reply text (remove quoted text from Gmail)\n let clientMessage = reply?.snippet || \"\";\n clientMessage = clientMessage.split(\"On Wed\")[0].trim(); // basic cleanup example\n\n // Prepare clean structured output\n return {\n json: {\n Email: reply?.From?.match(/<(.+?)>/)?.[1] || reply?.From || \"\",\n ContactPerson: reply?.From?.split(\"<\")[0].trim() || \"\",\n ThreadID: reply?.threadId || data.id || \"\",\n Subject: reply?.Subject || original?.Subject || \"\",\n ClientMessage: clientMessage,\n BookingStatus: \"BOOKED\",\n LastUpdated: new Date().toISOString()\n }\n };\n});\n"
},
"typeVersion": 2
},
{
"id": "3672ff59-f78b-42c3-b5d4-c311bd12bc09",
"name": "Log Invalid Leads to Google Sheets",
"type": "n8n-nodes-base.googleSheets",
"position": [
-352,
784
],
"parameters": {
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "list",
"value": "",
"cachedResultUrl": "",
"cachedResultName": ""
},
"documentId": {
"__rl": true,
"mode": "url",
"value": ""
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.6
},
{
"id": "fa1d3fb9-4316-473c-a98d-d86688288bc1",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2176,
-592
],
"parameters": {
"width": 976,
"height": 544,
"content": "## \ud83e\udd16 AI-Powered Outreach & Follow-Up Automation (GPT-4o + Gmail + Google Sheets)\nAutomates personalized outreach, follow-ups, and lead status management directly from Google Sheets using GPT-4o and Gmail.\n\n### \ud83d\udd39 Core Workflow Summary\n1\ufe0f\u20e3 Fetches leads from Google Sheets \n2\ufe0f\u20e3 Validates lead data and filters \u201cBOOKED\u201d prospects \n3\ufe0f\u20e3 Generates personalized outreach emails using GPT-4o \n4\ufe0f\u20e3 Sends emails via Gmail and monitors for replies \n5\ufe0f\u20e3 If no reply \u2192 Sends automated follow-up \n6\ufe0f\u20e3 Updates lead booking status automatically in Google Sheets\n\n### \ud83d\udd39 Tools & Integrations\n- Google Sheets \u2192 Lead database \n- Azure OpenAI (GPT-4o) \u2192 Email personalization \n- Gmail \u2192 Message delivery + reply tracking \n- JavaScript \u2192 Data cleanup and formatting \n- Wait nodes \u2192 Timing for recheck and follow-ups \n\n### \ud83d\udd39 Use Case\nIdeal for sales teams handling cold/warm leads who need to automate email outreach, monitor engagement, and maintain clean CRM updates \u2014 all without manual effort.\n"
},
"typeVersion": 1
},
{
"id": "396639c9-7361-4452-9d84-3d979e7823fb",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1008,
0
],
"parameters": {
"color": 7,
"height": 512,
"content": "## \ud83e\uddfe Retrieve Lead Records from Google Sheets \nPulls all lead data from the specified Google Sheet (\u201csample_leads_50\u201d). \nIncludes fields like company name, contact person, job title, industry, and booking status. \nActs as the entry point for the outreach campaign.\n"
},
"typeVersion": 1
},
{
"id": "7c0917c7-bbb8-493c-b795-7d0cbef9de56",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
-752,
48
],
"parameters": {
"color": 7,
"height": 448,
"content": "## \ud83e\udde9 Validate Lead Data Payload \nEnsures that each record has a valid email address format using regex. \nIf valid \u2192 proceeds to filtering. \nIf invalid \u2192 logs details to the \u201cInvalid Leads\u201d sheet.\n"
},
"typeVersion": 1
},
{
"id": "e4fd669c-4099-4fb2-ac1a-f8b50a0d957c",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
-464,
64
],
"parameters": {
"color": 7,
"height": 432,
"content": "## \ud83c\udfaf Filter for Booked Leads \nSeparates leads based on the \u201cBooking Status\u201d column. \nOnly unbooked or open leads proceed to email generation. \nPrevents re-contacting leads already converted or declined.\n"
},
"typeVersion": 1
},
{
"id": "91004249-8604-423c-9173-1510532b4c32",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
-80,
576
],
"parameters": {
"color": 7,
"height": 416,
"content": "## \u2699\ufe0f Configure GPT-4o Model \nLinks Azure OpenAI GPT-4o model for personalized email generation. \nEnsures each message is contextually relevant, professional, and concise.\n"
},
"typeVersion": 1
},
{
"id": "36b8dd72-9f4a-4f7a-b42f-16b917b7a7f7",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
-32,
-16
],
"parameters": {
"color": 7,
"width": 288,
"height": 528,
"content": "## \u2709\ufe0f Generate Personalized Outreach Email (AI) \nGPT-4o creates customized outreach messages for each lead using name, industry, and lead source context. \nOutput includes:\n- \u201csubject\u201d \u2192 catchy and relevant \n- \u201cbody_html\u201d \u2192 mobile-friendly HTML with <p> and <b> tags \nEnds with a polite CTA signed as \u201cSaurabh Garg, Sales Team.\u201d\n"
},
"typeVersion": 1
},
{
"id": "48df91f8-b98d-47ca-9ae1-7b18883531ea",
"name": "Sticky Note6",
"type": "n8n-nodes-base.stickyNote",
"position": [
384,
64
],
"parameters": {
"color": 7,
"height": 432,
"content": "## \ud83e\udde0 Parse AI Email Output (JavaScript) \nCleans GPT-4o output by removing code blocks and parsing JSON safely. \nEnsures valid `subject` and `body_html` fields before email dispatch.\n"
},
"typeVersion": 1
},
{
"id": "ea0c948b-46f5-4439-811f-b109d9f13b3a",
"name": "Sticky Note7",
"type": "n8n-nodes-base.stickyNote",
"position": [
704,
64
],
"parameters": {
"color": 7,
"height": 464,
"content": "## \ud83d\udce4 Send Initial Outreach Email via Gmail \nDelivers the AI-generated email to the lead\u2019s email address. \nUses Gmail OAuth for secure delivery. \nStores Gmail thread IDs for tracking replies.\n"
},
"typeVersion": 1
},
{
"id": "0d840272-78c6-4676-9e22-e80ed0c51c85",
"name": "Sticky Note8",
"type": "n8n-nodes-base.stickyNote",
"position": [
976,
96
],
"parameters": {
"color": 7,
"height": 432,
"content": "## \u23f1\ufe0f Wait Before Thread Check \nIntroduces a controlled delay (e.g., 24 hours) before checking if the lead has replied. \nEnsures enough time for recipients to respond naturally.\n"
},
"typeVersion": 1
},
{
"id": "d4508106-1715-400b-a4c4-1ae422647747",
"name": "Sticky Note9",
"type": "n8n-nodes-base.stickyNote",
"position": [
1232,
144
],
"parameters": {
"color": 7,
"width": 512,
"height": 400,
"content": "## \ud83e\udde9 Check for Client Reply \nFetches Gmail thread data to see if a response was received. \nIf the message contains any positive snippet or \u201cYes\u201d, marks lead as \u201cBOOKED.\u201d \nIf not, moves to follow-up sequence.\n"
},
"typeVersion": 1
},
{
"id": "d4b7826a-4119-4638-989d-7ced0c23cfb9",
"name": "Sticky Note10",
"type": "n8n-nodes-base.stickyNote",
"position": [
1856,
-224
],
"parameters": {
"color": 7,
"height": 464,
"content": "## \ud83d\udcec Extract Reply Details (JavaScript) \nParses client reply text and extracts useful data (email, message, thread ID). \nSanitizes Gmail snippets by removing quoted text. \nStores results for CRM update.\n"
},
"typeVersion": 1
},
{
"id": "cfb1aeb6-0030-45a8-aba9-8473abcbb64b",
"name": "Sticky Note11",
"type": "n8n-nodes-base.stickyNote",
"position": [
2160,
-256
],
"parameters": {
"color": 7,
"height": 496,
"content": "## \u2705 Update Lead Record \u2013 Booked (Google Sheets) \nUpdates the lead record in the main sheet with \u201cBOOKED\u201d status, reply message, and timestamp. \nMaintains real-time CRM hygiene.\n"
},
"typeVersion": 1
},
{
"id": "89803f2c-06ef-4ff5-aaab-37a21b4e3069",
"name": "Sticky Note12",
"type": "n8n-nodes-base.stickyNote",
"position": [
1824,
272
],
"parameters": {
"color": 7,
"height": 480,
"content": "## \ud83d\udd01 Send Second Follow-Up Email via Gmail \nIf no reply after the first email, sends a polite follow-up after 24 hours. \nTone remains professional and friendly, encouraging response without pressure.\n"
},
"typeVersion": 1
},
{
"id": "ef74ec33-bd55-4f50-baa8-7b8ee5b28953",
"name": "Sticky Note13",
"type": "n8n-nodes-base.stickyNote",
"position": [
2160,
304
],
"parameters": {
"color": 7,
"width": 208,
"height": 432,
"content": "## \u23f1\ufe0f Wait Before Thread Check \nIntroduces a controlled delay (e.g., 24 hours) before checking if the lead has replied. \nEnsures enough time for recipients to respond naturally.\n"
},
"typeVersion": 1
},
{
"id": "1fc0aee3-436a-4048-a8c7-1961a47ffec4",
"name": "Sticky Note14",
"type": "n8n-nodes-base.stickyNote",
"position": [
2432,
336
],
"parameters": {
"color": 7,
"height": 416,
"content": "## \ud83d\udce8 Fetch Follow-Up Thread from Gmail \nRetrieves the Gmail thread of the follow-up message to check if a new reply arrived.\n"
},
"typeVersion": 1
},
{
"id": "67182b47-ddba-47d2-be7c-ea3ad548d7a1",
"name": "Sticky Note15",
"type": "n8n-nodes-base.stickyNote",
"position": [
2720,
320
],
"parameters": {
"color": 7,
"height": 432,
"content": "## \ud83d\udd0d Check for Second Reply \nInspects the follow-up thread for responses. \nBranches into \u201cReply Found\u201d (update as BOOKED) or \u201cNo Reply\u201d (mark as Declined).\n"
},
"typeVersion": 1
},
{
"id": "833511eb-4e42-484c-ad8a-8bf59814b5a2",
"name": "Sticky Note16",
"type": "n8n-nodes-base.stickyNote",
"position": [
3088,
608
],
"parameters": {
"color": 7,
"width": 560,
"height": 384,
"content": "## \u274c Update Lead Record \u2013 Declined (Google Sheets) \nIf no response after follow-up, updates status to \u201cDeclined.\u201d \nPrevents repeated outreach and keeps CRM clean.\n"
},
"typeVersion": 1
},
{
"id": "99ffdfe2-e395-4004-acf7-3dfc51d5cfe6",
"name": "Sticky Note17",
"type": "n8n-nodes-base.stickyNote",
"position": [
3104,
0
],
"parameters": {
"color": 7,
"height": 432,
"content": "## \ud83e\uddfe Extract Second Reply Details (JavaScript) \nHandles cases where the client replied to the follow-up instead of the first message. \nParses, cleans, and prepares structured JSON data for CRM update.\n"
},
"typeVersion": 1
},
{
"id": "6570873f-5445-49cb-951d-9aa2014df10c",
"name": "Sticky Note18",
"type": "n8n-nodes-base.stickyNote",
"position": [
3376,
-32
],
"parameters": {
"color": 7,
"height": 496,
"content": "## \u2705 Update Lead Record \u2013 Booked (Google Sheets) \nUpdates the lead record in the main sheet with \u201cBOOKED\u201d status, reply message, and timestamp. \nMaintains real-time CRM hygiene.\n"
},
"typeVersion": 1
},
{
"id": "22fed90c-0601-421b-9079-3ca3652b1f9a",
"name": "Sticky Note19",
"type": "n8n-nodes-base.stickyNote",
"position": [
-416,
560
],
"parameters": {
"color": 7,
"height": 464,
"content": "## \u26a0\ufe0f Log Invalid Leads to Google Sheets \nStores invalid or incomplete entries (missing emails, broken data) in a separate sheet. \nUseful for data quality improvement.\n"
},
"typeVersion": 1
}
],
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "cc9e6722-fa25-48dc-b8cc-9060afd4be2e",
"connections": {
"Configure GPT-4o Model": {
"ai_languageModel": [
[
{
"node": "Generate Personalized Outreach Email (AI)",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Filter for Booked Leads": {
"main": [
[],
[
{
"node": "Generate Personalized Outreach Email (AI)",
"type": "main",
"index": 0
}
]
]
},
"Validate Lead Data Payload": {
"main": [
[
{
"node": "Filter for Booked Leads",
"type": "main",
"index": 0
}
],
[
{
"node": "Log Invalid Leads to Google Sheets",
"type": "main",
"index": 0
}
]
]
},
"Wait Before Thread Check (24 hr)": {
"main": [
[
{
"node": "Fetch Sent Email Thread from Gmail",
"type": "main",
"index": 0
}
]
]
},
"Fetch Follow-Up Thread from Gmail": {
"main": [
[
{
"node": "Check for Second Reply (If Condition)",
"type": "main",
"index": 0
}
]
]
},
"Extract Reply Details (JavaScript)": {
"main": [
[
{
"node": "Update Lead Record \u2013 Booked (Google Sheets)",
"type": "main",
"index": 0
}
]
]
},
"Fetch Sent Email Thread from Gmail": {
"main": [
[
{
"node": "Check for Client Reply (If Condition)",
"type": "main",
"index": 0
}
]
]
},
"Parse AI Email Output (JavaScript)": {
"main": [
[
{
"node": "Send Initial Outreach Email via Gmail",
"type": "main",
"index": 0
}
]
]
},
"When clicking \u2018Execute workflow\u2019": {
"main": [
[
{
"node": "Retrieve Lead Records from Google Sheets",
"type": "main",
"index": 0
}
]
]
},
"Check for Client Reply (If Condition)": {
"main": [
[
{
"node": "Extract Reply Details (JavaScript)",
"type": "main",
"index": 0
}
],
[
{
"node": "Send Second Follow-Up Email via Gmail",
"type": "main",
"index": 0
}
]
]
},
"Check for Second Reply (If Condition)": {
"main": [
[
{
"node": "Extract Second Reply Details (JavaScript)",
"type": "main",
"index": 0
}
],
[
{
"node": "Update Lead Status to Declined (Set Node)",
"type": "main",
"index": 0
}
]
]
},
"Send Initial Outreach Email via Gmail": {
"main": [
[
{
"node": "Wait Before Thread Check (24 hr)",
"type": "main",
"index": 0
}
]
]
},
"Send Second Follow-Up Email via Gmail": {
"main": [
[
{
"node": "Wait Before Second Thread Check (24 hr)",
"type": "main",
"index": 0
}
]
]
},
"Wait Before Second Thread Check (24 hr)": {
"main": [
[
{
"node": "Fetch Follow-Up Thread from Gmail",
"type": "main",
"index": 0
}
]
]
},
"Retrieve Lead Records from Google Sheets": {
"main": [
[
{
"node": "Validate Lead Data Payload",
"type": "main",
"index": 0
}
]
]
},
"Extract Second Reply Details (JavaScript)": {
"main": [
[
{
"node": "Update Lead Record \u2013 Replied (Google Sheets)",
"type": "main",
"index": 0
}
]
]
},
"Generate Personalized Outreach Email (AI)": {
"main": [
[
{
"node": "Parse AI Email Output (JavaScript)",
"type": "main",
"index": 0
}
]
]
},
"Update Lead Status to Declined (Set Node)": {
"main": [
[
{
"node": "Update Lead Record \u2013 Declined (Google Sheets)",
"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.
azureOpenAiApigmailOAuth2googleSheetsOAuth2Api
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Automate your AI-powered outreach and follow-up pipeline end-to-end with GPT-4o, Gmail, and Google Sheets. π€π¬ This workflow personalizes emails for each lead, manages follow-ups automatically, tracks client replies, and updates CRM records in real time β all from a single Googleβ¦
Source: https://n8n.io/workflows/10827/ β original creator credit. Request a take-down β
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
This workflow automates the creation, storage, and reporting of personalized sales collateral for booked leads using GPT-4o, Google Sheets, Google Drive, and Gmail. It pulls leads from a central sheet
This workflow automates end-to-end validation, assessment, and reporting of n8n workflow JSON templates using Google Drive, Azure OpenAI GPT-4o, Gmail, and Slack. It retrieves workflows from a Drive f
Automatically capture customer onboarding help requests from Typeform, log them in Google Sheets, validate email addresses, and send a professional HTML welcome email via Gmail. Ensures smooth onboard
Automate customer feedback analysis and action planning by integrating Monday.com, Azure OpenAI, Jira, Google Sheets, and Outlook. This workflow classifies customer feedback with AI, calculates busine
Automatically generate polished, n8n-ready template descriptions from your saved JSON workflows in Google Drive. This AI-powered automation processes workflow files, drafts compliant descriptions, and