This workflow follows the Execute Workflow Trigger → 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 →
{
"meta": {
"versionId": "1.0.0",
"createdAt": "2025-09-29T07:07:42.514174",
"updatedAt": "2025-09-29T07:07:42.514194",
"owner": "n8n-user",
"license": "MIT",
"category": "automation",
"status": "active",
"priority": "high",
"environment": "production"
},
"nodes": [
{
"id": "8565747a-4108-4467-98e4-f57d441f66af",
"name": "Update last contacted time",
"type": "n8n-nodes-base.googleSheets",
"position": [
2380,
140
],
"parameters": {
"columns": {
"value": {
"row_number": "={{ $('To email?').item.json.row_number }}",
"first_emailed": "={{ $now.format('yyyy-MM-dd') }}"
},
"schema": [
{
"id": "email",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "email",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "first_emailed",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "first_emailed",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "name",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "name",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "company",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "company",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "row_number",
"type": "string",
"display": true,
"removed": false,
"readOnly": true,
"required": false,
"displayName": "row_number",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [
"row_number"
]
},
"options": {},
"operation": "update",
"sheetName": {
"__rl": true,
"mode": "url",
"value": "={{ $('Settings').item.json.sheet_url }}"
},
"documentId": {
"__rl": true,
"mode": "url",
"value": "={{ $('Settings').item.json.sheet_url }}"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.2,
"notes": "This googleSheets node performs automated tasks as part of the workflow."
},
{
"id": "5f079ac7-1bef-4bb8-8efe-1f3803357fb1",
"name": "Set message template",
"type": "n8n-nodes-base.set",
"disabled": true,
"position": [
1500,
1120
],
"parameters": {
"fields": {
"values": [
{
"name": "message_template",
"stringValue": "={{ $('Email sequence').first().json.emails[0].message }}"
},
{
"name": "email",
"stringValue": "you@example.com"
},
{
"name": "name",
"stringValue": "Daffyd"
},
{
"name": "company",
"stringValue": "Davey Enterprises"
},
{
"name": "subject",
"stringValue": "={{ $('Settings').item.json.subject }}"
},
{
"name": "sender_name",
"stringValue": "={{ $('Settings').item.json.sender_name }}"
},
{
"name": "mail_id",
"stringValue": "={{ $('Settings').item.json.mail_id }}"
},
{
"name": "mail_seq",
"stringValue": "0"
}
]
},
"include": "none",
"options": {}
},
"typeVersion": 3.2,
"notes": "This set node performs automated tasks as part of the workflow."
},
{
"id": "7ff4eabc-f49a-4adc-9a4b-750585b72070",
"name": "Email sequence",
"type": "n8n-nodes-base.set",
"position": [
1000,
140
],
"parameters": {
"mode": "raw",
"options": {},
"jsonOutput": "{\n \"emails\": [\n {\n \"message\": \"Hi {name}, hope you're well!<br />\\n<br />\\nYou're doing some great things at {company}, and I wanted to touch base to see if you wanted to chat.<br />\\n<br />\\nWould it make sense to jump on a quick call?<br />\\n<br />\\nRegards,<br />\\n<br />\\nNathan<br />\\n\",\n \"send_on_day\": 0\n },\n {\n \"message\": \"Hi {name},<br />\\n<br />\\nJust wanted to follow up on this, since it would be great to talk.<br />\\n<br />\\nRegards,<br />\\n<br />\\nNathan<br />\\n\",\n \"send_on_day\": 3\n },\n {\n \"message\": \"Just thought I'd give this one last try :)<br />\\n<br />\\nNathan\\n\",\n \"send_on_day\": 8\n }\n ]\n}\n"
},
"typeVersion": 3.2,
"notes": "This set node performs automated tasks as part of the workflow."
},
{
"id": "7b038199-cf02-4536-a351-b86d51b0d367",
"name": "Fill message placeholders",
"type": "n8n-nodes-base.code",
"position": [
1720,
1120
],
"parameters": {
"mode": "runOnceForEachItem",
"jsCode": "function extractPlaceholders(str) {\n // Regular expression to match placeholders\n // It matches any alphanumeric character including dashes and underscores between {}\n const regex = /\\{([a-zA-Z0-9_-]+)\\}/g;\n \n // Set to store unique placeholders\n const uniquePlaceholders = new Set();\n\n // Extract and store unique placeholders\n let match;\n while ((match = regex.exec(str)) !== null) {\n uniquePlaceholders.add(match[1]);\n }\n\n // Convert the Set to an array and return\n return Array.from(uniquePlaceholders);\n}\n\nlet placeholders = Object.keys(item.json.placeholders)\nconsole.log(placeholders)\n\n// Substitute all the placeholders in the message\n item.json.message = item.json.message_template\n for (let key of extractPlaceholders(item.json.message_template)) {\n if(!placeholders.includes(key)) throw new Error(`Missing data for placeholder '{${key}}'`)\n const regex = new RegExp(`\\\\{${key}\\\\}`, 'g'); // Create a regex to match the exact word surrounded by {}\n item.json.message = item.json.message.replaceAll(regex, item.json.placeholders[key]);\n }\n\nreturn item"
},
"typeVersion": 2,
"notes": "This code node performs automated tasks as part of the workflow."
},
{
"id": "42fe4448-1a44-47aa-a04b-927d441b265a",
"name": "Compose message",
"type": "n8n-nodes-base.set",
"position": [
1940,
1120
],
"parameters": {
"fields": {
"values": [
{
"name": "message",
"stringValue": "=<span data-cam='{{ $json.mail_id }}' data-seq='{{ $json.mail_seq }}' data-ph='{{ JSON.stringify($json.placeholders) }}'></span>{{ $json.message }}"
}
]
},
"options": {}
},
"typeVersion": 3.2,
"notes": "This set node performs automated tasks as part of the workflow."
},
{
"id": "bccf2e89-852e-49b4-ad98-194008c47760",
"name": "Get previous message threads",
"type": "n8n-nodes-base.gmail",
"position": [
1280,
620
],
"parameters": {
"filters": {
"q": "=subject:{{ $json.subject }} after:{{ $now.minus({'days': $json.emails.last().send_on_day+1}).toSQL().substr(0, 10) }}"
},
"resource": "thread",
"returnAll": true
},
"credentials": {
"gmailOAuth2": {
"name": "<your credential>"
}
},
"typeVersion": 2.1,
"notes": "This gmail node performs automated tasks as part of the workflow."
},
{
"id": "3ce6c45f-a257-4270-a84d-6a19ec35b2eb",
"name": "Get thread details",
"type": "n8n-nodes-base.gmail",
"position": [
1500,
620
],
"parameters": {
"simple": false,
"options": {},
"resource": "thread",
"threadId": "={{ $json.id }}",
"operation": "get"
},
"credentials": {
"gmailOAuth2": {
"name": "<your credential>"
}
},
"typeVersion": 2,
"notes": "This gmail node performs automated tasks as part of the workflow."
},
{
"id": "9224bb16-fbc2-45b5-a2cb-f63cb440f46f",
"name": "Classify threads",
"type": "n8n-nodes-base.code",
"position": [
1940,
620
],
"parameters": {
"jsCode": "// Because emails are sent slightly after the schedule trigger runs, we'll end up waiting an extra day to send unless we take into account the execution time of the workflow\nlet buffer_mins = 20\n\nlet templates = $('Email sequence').first().json.emails\n\nfunction next_sequence_number(messages, mail_id, sender_name) {\n for (let i = 0; i < messages.length; i++) {\n if(!('html' in messages[i])) return -1;\n let in_campaign = messages[i].html.includes(\"data-cam='\"+mail_id+\"'\")\n let valid_seq = messages[i].html.includes(\"data-seq='\"+i+\"'\")\n let from_us = messages[i].From.includes(sender_name)\n console.log(in_campaign + \", \" + valid_seq + \", \" + from_us)\n if(!(from_us && in_campaign && valid_seq)) {\n return -1;\n }\n }\n return messages.length;\n}\n\n\nfor (const item of $input.all()) {\n item.json.first_message_at = DateTime.fromMillis($('Get thread details').item.json.messages[0].internalDate*1)\n item.json.days_since_first_message = DateTime.now().diff(item.json.first_message_at, 'days').days\n item.json.next_sequence_number = next_sequence_number(\n item.json.messages,\n $('Settings').first().json.mail_id,\n $('Settings').first().json.sender_name\n );\n item.json.next_message_due = (\n item.json.next_sequence_number > 0\n && item.json.next_sequence_number < templates.length\n && templates[item.json.next_sequence_number].send_on_day <= item.json.days_since_first_message + (buffer_mins/60/24)\n )\n\n // Retrieve the placeholder values from the snippet, for use in future messages\n const ph_matches = item.json.messages[0].snippet.match(/data-ph='([^']*)'/)\n if(ph_matches?.length > 1) {\n const placeholders = JSON.parse(ph_matches[1])\n for(key of placeholders.keys()) {\n item.json[key] = placeholders[key]\n }\n }\n\n}\n\nreturn $input.all();"
},
"typeVersion": 2,
"notes": "This code node performs automated tasks as part of the workflow."
},
{
"id": "776cb743-339d-49f6-af3c-9ae2b464d01a",
"name": "Next message due?",
"type": "n8n-nodes-base.filter",
"position": [
2160,
620
],
"parameters": {
"options": {},
"conditions": {
"options": {
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "00cf6401-f45a-4496-803c-70a5b2d7daf5",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
},
"leftValue": "={{ $json.next_message_due }}",
"rightValue": ""
}
]
}
},
"typeVersion": 2,
"notes": "This filter node performs automated tasks as part of the workflow."
},
{
"id": "2ecf68b5-f5bf-4961-a849-7c0d29940387",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
1906,
427
],
"parameters": {
"color": 7,
"width": 181.66573318934627,
"height": 344.96230939963334,
"content": "Follow-up is due if:\n- All the messages in the thread are automated (no-one has replied yet)\n- Enough time has passed for the next message to be sent"
},
"typeVersion": 1,
"notes": "This stickyNote node performs automated tasks as part of the workflow."
},
{
"id": "a3a78abb-0691-4152-a349-658b8286df2f",
"name": "Execute Workflow Trigger",
"type": "n8n-nodes-base.executeWorkflowTrigger",
"position": [
1280,
1120
],
"parameters": {},
"typeVersion": 1,
"notes": "This executeWorkflowTrigger node performs automated tasks as part of the workflow."
},
{
"id": "a62bff23-2742-4a5e-8896-e1a3be5915fd",
"name": "Replying?",
"type": "n8n-nodes-base.if",
"position": [
2160,
1120
],
"parameters": {
"options": {},
"conditions": {
"options": {
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "dc8ec88f-daef-46be-b3da-1407d5e1c0b1",
"operator": {
"type": "string",
"operation": "exists",
"singleValue": true
},
"leftValue": "={{ $json.reply_message_id }}",
"rightValue": ""
}
]
}
},
"typeVersion": 2,
"notes": "This if node performs automated tasks as part of the workflow."
},
{
"id": "76d25df2-4472-40a6-80c6-f2e3dc8702a3",
"name": "Send new message",
"type": "n8n-nodes-base.gmail",
"position": [
2380,
1240
],
"parameters": {
"sendTo": "={{ $json.to_email }}",
"message": "={{ $json.message }}",
"options": {
"senderName": "={{ $json.sender_name }}",
"appendAttribution": false
},
"subject": "={{ $json.subject }}"
},
"credentials": {
"gmailOAuth2": {
"name": "<your credential>"
}
},
"typeVersion": 2.1,
"notes": "This gmail node performs automated tasks as part of the workflow."
},
{
"id": "ceefaf78-28b8-4711-b50e-b5487862dba6",
"name": "Call message send sub-workflow",
"type": "n8n-nodes-base.executeWorkflow",
"position": [
2820,
620
],
"parameters": {
"options": {},
"workflowId": "={{ $workflow.id }}"
},
"typeVersion": 1,
"notes": "This executeWorkflow node performs automated tasks as part of the workflow."
},
{
"id": "809e9df8-881a-4b32-a3c0-e55c669bd8d1",
"name": "Prepare reply params",
"type": "n8n-nodes-base.set",
"position": [
2380,
620
],
"parameters": {
"fields": {
"values": [
{
"name": "message_template",
"stringValue": "={{ $('Email sequence').first().json.emails[$json.next_sequence_number].message }}"
},
{
"name": "reply_message_id",
"stringValue": "={{ $json.messages.last().id }}"
},
{
"name": "sender_name",
"stringValue": "={{ $('Settings').item.json.sender_name }}"
},
{
"name": "mail_id",
"stringValue": "={{ $('Settings').item.json.mail_id }}"
},
{
"name": "mail_seq",
"stringValue": "={{ $json.next_sequence_number }}"
},
{
"name": "to",
"stringValue": "={{ $json.messages[0].To }}"
}
]
},
"include": "none",
"options": {}
},
"typeVersion": 3.2,
"notes": "This set node performs automated tasks as part of the workflow."
},
{
"id": "cdda96f1-e0a2-4ce8-bc78-da8e80f7029f",
"name": "Prepare first message params",
"type": "n8n-nodes-base.set",
"position": [
1720,
140
],
"parameters": {
"fields": {
"values": [
{
"name": "message_template",
"stringValue": "={{ $('Email sequence').first().json.emails[0].message }}"
},
{
"name": "to_email",
"stringValue": "={{ $('Get emails').item.json[$('Settings').item.json.email_column_name] }}"
},
{
"name": "subject",
"stringValue": "={{ $('Settings').item.json.subject }}"
},
{
"name": "sender_name",
"stringValue": "={{ $('Settings').item.json.sender_name }}"
},
{
"name": "mail_id",
"stringValue": "={{ $('Settings').item.json.mail_id }}"
},
{
"name": "mail_seq",
"stringValue": "0"
}
]
},
"options": {}
},
"typeVersion": 3.2,
"notes": "This set node performs automated tasks as part of the workflow."
},
{
"id": "c2d9869e-0608-472a-a124-26e9e6f1820a",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
1240,
-100
],
"parameters": {
"color": 7,
"width": 181.66573318934627,
"height": 410.4105111871959,
"content": "Columns the sheet needs\n- email\n- first_emailed (leave blank - will be filled in automatically)\n- Other columns matching placeholders in email sequence"
},
"typeVersion": 1,
"notes": "This stickyNote node performs automated tasks as part of the workflow."
},
{
"id": "26bc2c58-fea5-4ee0-b9ea-264ad00e8d32",
"name": "Call message send sub-workflow1",
"type": "n8n-nodes-base.executeWorkflow",
"position": [
2160,
140
],
"parameters": {
"mode": "each",
"options": {},
"workflowId": "={{ $workflow.id }}"
},
"typeVersion": 1,
"notes": "This executeWorkflow node performs automated tasks as part of the workflow."
},
{
"id": "e7e7d9bd-79c6-4534-b88d-b54cc695c7bf",
"name": "To email?",
"type": "n8n-nodes-base.filter",
"position": [
1500,
140
],
"parameters": {
"options": {},
"conditions": {
"options": {
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "eeec5901-5ff0-47b1-926b-e93097d64434",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
},
"leftValue": "={{ $json.first_emailed.isEmpty() }}",
"rightValue": ""
}
]
}
},
"typeVersion": 2,
"notes": "This filter node performs automated tasks as part of the workflow."
},
{
"id": "db4b6481-5fdb-4bc3-a10f-b6ccfb5b0bf0",
"name": "Decode messages",
"type": "n8n-nodes-base.code",
"position": [
1720,
620
],
"parameters": {
"jsCode": "// TODO: Some messages have an empty payload and a parts field instead (containing an array)\n\nfor (const item of $input.all()) {\n for (const message of item.json.messages) {\n console.log('message', message.payload.body.data || \"\")\n let buffer = Buffer.from(message.payload.body.data || \"\", \"base64\");\n message.html = buffer.toString(\"utf8\")\n }\n}\n\nreturn $input.all();"
},
"typeVersion": 2,
"notes": "This code node performs automated tasks as part of the workflow."
},
{
"id": "fc4868f0-845d-4f76-a566-b0db3d2676f8",
"name": "Decode placeholder values",
"type": "n8n-nodes-base.code",
"position": [
2600,
620
],
"parameters": {
"mode": "runOnceForEachItem",
"jsCode": "const html = $('Decode messages').item.json.messages[0].html\nconst matches = html.match(/data-ph='([^']*)'/)\nlet placeholders = {}\nif(matches?.length > 0) {\n ph = JSON.parse(matches[1])\n for(k of Object.keys(ph)) {\n placeholders[k] = ph[k]\n }\n}\nitem.json.placeholders = placeholders\n\nreturn item;"
},
"typeVersion": 2,
"notes": "This code node performs automated tasks as part of the workflow."
},
{
"id": "5af9b08e-6c5d-4701-a44a-794e96216948",
"name": "Package placeholder values",
"type": "n8n-nodes-base.code",
"position": [
1940,
140
],
"parameters": {
"mode": "runOnceForEachItem",
"jsCode": "function extractPlaceholders(str) {\n // Regular expression to match placeholders\n // It matches any alphanumeric character including dashes and underscores between {}\n const regex = /\\{([a-zA-Z0-9_-]+)\\}/g;\n \n // Set to store unique placeholders\n const uniquePlaceholders = new Set();\n\n // Extract and store unique placeholders\n let match;\n while ((match = regex.exec(str)) !== null) {\n uniquePlaceholders.add(match[1]);\n }\n\n // Convert the Set to an array and return\n return Array.from(uniquePlaceholders);\n}\n\n\n// Gather all the placeholder values for passing on\nconst all_ph_raw = $('Email sequence').first().json.emails.flatMap(e => extractPlaceholders(e.message))\nconst all_ph = [...new Set(all_ph_raw)];\nlet placeholders = {}\nfor(ph of all_ph) {\n if($('Get emails').item.json[ph] == undefined) throw new Error(`Message placeholder '{${ph}}' requires a column called '${ph}' in the Google Sheet`)\n placeholders[ph] = $('Get emails').item.json[ph]\n}\n\nitem.json.placeholders = placeholders\n\nreturn item;"
},
"typeVersion": 2,
"notes": "This code node performs automated tasks as part of the workflow."
},
{
"id": "e655a9c2-617b-4119-9582-45f1db2cc6d2",
"name": "Settings",
"type": "n8n-nodes-base.set",
"position": [
780,
140
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "5e327a1d-3f2e-40f1-aaa1-9ce888349eb0",
"name": "sheet_url",
"type": "string",
"value": "{{ $env.WEBHOOK_URL }}"
},
{
"id": "3255270a-3ac2-4c59-8215-ea79256b55cc",
"name": "subject",
"type": "string",
"value": "My amazing campaign"
},
{
"id": "76b40b74-acef-49f1-a0e2-0be9a461319a",
"name": "sender_name",
"type": "string",
"value": "Nathan Automat"
},
{
"id": "4532eb84-5ebc-4011-8c65-d97aeae21256",
"name": "email_column_name",
"type": "string",
"value": "email"
},
{
"id": "83de0ceb-39ec-426a-afba-13d66bce101d",
"name": "mail_id",
"type": "string",
"value": "123456"
}
]
}
},
"typeVersion": 3.3,
"notes": "This set node performs automated tasks as part of the workflow."
},
{
"id": "a8975f91-6413-448b-bc3f-1084959b8b31",
"name": "Reply to message",
"type": "n8n-nodes-base.gmail",
"position": [
2380,
1020
],
"parameters": {
"message": "={{ $json.message }}",
"options": {
"senderName": "David Roberts"
},
"messageId": "={{ $json.reply_message_id }}",
"operation": "reply"
},
"credentials": {
"gmailOAuth2": {
"name": "<your credential>"
}
},
"typeVersion": 2,
"notes": "This gmail node performs automated tasks as part of the workflow."
},
{
"id": "d453661e-25f7-471c-90dc-633270f14396",
"name": "Get emails",
"type": "n8n-nodes-base.googleSheets",
"position": [
1280,
140
],
"parameters": {
"options": {},
"sheetName": {
"__rl": true,
"mode": "url",
"value": "={{ $('Settings').item.json.sheet_url }}"
},
"documentId": {
"__rl": true,
"mode": "url",
"value": "={{ $('Settings').item.json.sheet_url }}"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.2,
"notes": "This googleSheets node performs automated tasks as part of the workflow."
},
{
"id": "7a838728-38e1-45f9-8bac-19c6ad005a38",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
1220,
-180
],
"parameters": {
"color": 7,
"width": 1790.5345476157208,
"height": 515.1374038700677,
"content": "## Send initial emails"
},
"typeVersion": 1,
"notes": "This stickyNote node performs automated tasks as part of the workflow."
},
{
"id": "5d8823c1-00a7-43a2-963d-90e971167ef8",
"name": "Sticky Note6",
"type": "n8n-nodes-base.stickyNote",
"position": [
1220,
360
],
"parameters": {
"color": 7,
"width": 1797.4980261229769,
"height": 515.1374038700677,
"content": "## Send follow-up emails if appropriate"
},
"typeVersion": 1,
"notes": "This stickyNote node performs automated tasks as part of the workflow."
},
{
"id": "fd2bb0b2-a313-45ed-ad58-935d803237e5",
"name": "Sticky Note7",
"type": "n8n-nodes-base.stickyNote",
"position": [
1220,
920
],
"parameters": {
"color": 7,
"width": 1797.4980261229769,
"height": 515.1374038700677,
"content": "## Sub-workflow for sending the emails\nThis is called by the sections above - you shouldn't need to touch it"
},
"typeVersion": 1,
"notes": "This stickyNote node performs automated tasks as part of the workflow."
},
{
"id": "be4a4bbb-1e10-4c9e-afb9-cc4a46a78113",
"name": "Every hour",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
320,
140
],
"parameters": {
"rule": {
"interval": [
{
"field": "hours",
"triggerAtMinute": 12
}
]
}
},
"typeVersion": 1.1,
"notes": "This scheduleTrigger node performs automated tasks as part of the workflow."
},
{
"id": "be582e38-6da2-4c64-8804-981936f71d88",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
2120,
958
],
"parameters": {
"color": 7,
"width": 181.66573318934627,
"height": 306.5470605243249,
"content": "If reply_message_id is set, will reply to that message.\n\nOtherwise, will send a new message to the user in the 'email' field"
},
"typeVersion": 1,
"notes": "This stickyNote node performs automated tasks as part of the workflow."
},
{
"id": "88e9ff03-62f0-4dcf-9e28-62c95386df66",
"name": "Don't email on weekends",
"type": "n8n-nodes-base.filter",
"position": [
540,
140
],
"parameters": {
"options": {},
"conditions": {
"options": {
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "195ce0cf-9d25-4e02-9f20-aa6edbc2d561",
"operator": {
"type": "boolean",
"operation": "false",
"singleValue": true
},
"leftValue": "={{ $now.isWeekend() }}",
"rightValue": ""
}
]
}
},
"typeVersion": 2,
"notes": "This filter node performs automated tasks as part of the workflow."
},
{
"id": "7a5822f3-b2ea-42d7-8034-21a92e283112",
"name": "Sticky Note8",
"type": "n8n-nodes-base.stickyNote",
"position": [
740,
-120
],
"parameters": {
"width": 404.04123613412946,
"height": 418.96364526464185,
"content": "# Try me out\n1. Clone [this Google worksheet]({{ $env.WEBHOOK_URL }} and update the 'Settings' node with its URL (plus change any other settings there you need to)\n2. Adjust the sequence of emails you want to send in the 'Email Sequence' node\n\nMake sure you set how many days after the previous email to wait before sending, and note that the emails are in HTML format."
},
"typeVersion": 1,
"notes": "This stickyNote node performs automated tasks as part of the workflow."
},
{
"id": "error-7158d4e1",
"name": "Error Handler",
"type": "n8n-nodes-base.stopAndError",
"typeVersion": 1,
"position": [
1000,
400
],
"parameters": {
"message": "Workflow execution error",
"options": {}
}
}
],
"connections": {
"Update last contacted time": {
"main": [
[]
]
},
"Get emails": {
"main": [
[]
]
}
},
"name": "Googlesheets Workflow",
"settings": {
"executionOrder": "v1",
"saveManualExecutions": true,
"callerPolicy": "workflowsFromSameOwner",
"errorWorkflow": null,
"timezone": "UTC",
"executionTimeout": 3600,
"maxExecutions": 1000,
"retryOnFail": true,
"retryCount": 3,
"retryDelay": 1000
},
"description": "Automated workflow: Googlesheets Workflow. This workflow integrates 11 different services: filter, stickyNote, code, scheduleTrigger, set. It contains 34 nodes and follows best practices for error handling and security.",
"notes": "Excellent quality workflow: Googlesheets Workflow. This workflow has been optimized for production use with comprehensive error handling, security, and documentation.",
"id": "wfe3649df6681a"
}
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.
gmailOAuth2googleSheetsOAuth2Api
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Googlesheets Workflow. Uses googleSheets, gmail, executeWorkflowTrigger, stopAndError. Event-driven trigger; 33 nodes.
Source: https://github.com/basictechorg/n8n-productivity/blob/main/workflows/email-automation/0437_Code_Filter_Create_Scheduled.json — 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.
Splitout Code. Uses manualTrigger, httpRequest, stickyNote, splitOut. Event-driven trigger; 46 nodes.
Automate CSV imports into HubSpot without the mess. Powered by n8n. Supercharged by Pollup AI.
Categories: Payments, Project Operations, Client Onboarding
Code Filter. Uses googleSheets, gmail, stickyNote, executeWorkflowTrigger. Event-driven trigger; 32 nodes.
This n8n workflow enables teams to automate and standardize multi-step onboarding or messaging workflows using Google Sheets, Forms, Gmail, and dynamic logic powered by Code and Switch nodes. It ensur