This workflow corresponds to n8n.io template #16249 — we link there as the canonical source.
This workflow follows the Agent → Chat Trigger 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": "FFWaoXQ5I0HX8xN1",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "Email sending and tracking",
"tags": [],
"nodes": [
{
"id": "60885e38-6e19-4bf4-899a-e793a22d98e4",
"name": "Tracking Webhook",
"type": "n8n-nodes-base.webhook",
"position": [
-896,
640
],
"parameters": {
"path": "email-open-track",
"options": {},
"responseMode": "responseNode"
},
"typeVersion": 2
},
{
"id": "0f3f1f16-7ad8-4685-921a-26364e45b1a1",
"name": "Set Pixel And Metadata",
"type": "n8n-nodes-base.set",
"position": [
-560,
640
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "2c3b4d7a-b64a-42be-b775-6ca4097673b1",
"name": "query.email",
"type": "string",
"value": "={{ $json.query.email }}"
},
{
"id": "85187f32-6bc7-403b-b2cf-22e7cb45927d",
"name": "query.name",
"type": "string",
"value": "={{ $json.query.name }}"
},
{
"id": "016d7890-74fe-43e8-be49-af052a7bde33",
"name": "query.subject",
"type": "string",
"value": "={{ $json.query.subject }}"
},
{
"id": "b0eecc2b-e955-409b-940f-1c384957215a",
"name": "headers[\"x-real-ip\"]",
"type": "string",
"value": "={{ $json.headers[\"x-real-ip\"] }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "f368b045-5e9c-4b74-a2c1-143ed92759e5",
"name": "Send Open Notification",
"type": "n8n-nodes-base.gmail",
"position": [
112,
640
],
"parameters": {
"sendTo": "patelravi7210@gmail.com",
"message": "=Tracking pixel was loaded.\n\nEmail: {{ $('Set Pixel And Metadata').item.json.query.email }}\n\nSubject: {{ $('Set Pixel And Metadata').item.json.query.subject }}\n\nOpened at: {{ $json.currentDate }}",
"options": {
"appendAttribution": false
},
"subject": "=Email opened:{{ $('Set Pixel And Metadata').item.json.query.email }} subject {{ $('Set Pixel And Metadata').item.json.query.subject }}",
"emailType": "text"
},
"credentials": {
"gmailOAuth2": {
"name": "<your credential>"
}
},
"typeVersion": 2.1
},
{
"id": "520cc970-0d9d-48b8-aa7b-b05ffd0f7904",
"name": "When chat message received",
"type": "@n8n/n8n-nodes-langchain.chatTrigger",
"position": [
-896,
-192
],
"parameters": {
"options": {}
},
"typeVersion": 1.4
},
{
"id": "b7e0db14-5894-4193-a8a0-c7689c117b1d",
"name": "AI Agent",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
-608,
-192
],
"parameters": {
"text": "=You are an expert cold email writer.\n\nYour task:\nI will give you only an ACTION at last as action, company profile URL, LinkedIn profile URL, website URL, job post URL, or any text context.\n\nYou must automatically:\n\n1. Extract the recipient's name.\n2. Identify their company, role, industry, and relevant context.\n3. Understand the action I want to take.\n4. Create a personalized cold email.\n5. Use simple, natural English.\n6. Avoid AI-sounding language, buzzwords, hype, and generic compliments.\n7. Keep the email between 90 and 120 words.\n8. Include only one clear CTA.\n9. Personalize the first sentence based on the provided context.\n10. Sign the email as:\n Your Name\n\nOutput format:\n\nRecipient Name: [Name]\nEmail: [Email if available, otherwise N/A]\n\nSubject: [Subject Line]\n\nEmail Body:\n[Complete email]\n\nRules:\n\n* No markdown.\n* No bullet points inside the email.\n* No emojis.\n* No fake information.\n* If recipient details are missing, infer as much as possible from the provided context.\n* Make the email sound like it was written by a real person.\n* Focus on relevance, not selling.\n* Return only the final formatted output.\naction: {{ $json.chatInput }}\n",
"options": {},
"promptType": "define"
},
"typeVersion": 2
},
{
"id": "cabd8f4a-99b1-4da6-8d3a-b3bc7d20838c",
"name": "Google Gemini Chat Model",
"type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
"position": [
-608,
-16
],
"parameters": {
"options": {},
"modelName": "models/gemma-4-31b-it"
},
"credentials": {
"googlePalmApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.1
},
{
"id": "61a8ef14-c654-4651-b3a6-5c6741452d23",
"name": "Parse AI Output",
"type": "n8n-nodes-base.code",
"disabled": true,
"position": [
-192,
-192
],
"parameters": {
"jsCode": "const raw = $json.output || $json.text || '';\n\nconst getValue = (label) => {\n const match = raw.match(new RegExp(`${label}:\\\\s*([\\\\s\\\\S]*?)(?=\\\\n(?:Recipient Name|Email|Subject|Email Body):|$)`, 'i'));\n return match ? match[1].trim() : '';\n};\n\nconst recipientName = getValue('Recipient Name');\nconst toEmail = getValue('Email');\nconst subjectFromAi = getValue('Subject');\nconst textBody = getValue('Email Body');\n\nif (!toEmail || toEmail.toLowerCase() === 'n/a') {\n throw new Error('Recipient email missing in AI output');\n}\n\nreturn [{\n json: {\n chatInput: $json.chatInput,\n recipientName,\n toEmail,\n subject: subjectFromAi || `Quick idea for ${recipientName || 'there'}`,\n textBody\n }\n}];"
},
"typeVersion": 2
},
{
"id": "277aa578-e3f2-4647-b912-3ff800547ee3",
"name": "Generate Tracking ID",
"type": "n8n-nodes-base.code",
"position": [
128,
-192
],
"parameters": {
"jsCode": "const crypto = require('crypto');\nconst trackingId = crypto.randomUUID();\nconst subject = $json.subject || 'Quick idea';\nconst trackingUrl = `\"webhook url from tracking webhook node\"?id=${encodeURIComponent(trackingId)}&email=${encodeURIComponent($json.toEmail)}&name=${encodeURIComponent($json.recipientName || '')}&subject=${encodeURIComponent(subject)}`;\nreturn [{ json: { ...$json, trackingId, trackingUrl } }];"
},
"typeVersion": 2
},
{
"id": "d07fff12-3bac-40f0-85fa-098f6ef1f1e9",
"name": "Build HTML Email",
"type": "n8n-nodes-base.code",
"position": [
496,
-192
],
"parameters": {
"jsCode": "const escapeHtml = (str='') => str\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\\\"/g, '"')\n .replace(/'/g, ''');\n\nconst paragraphs = ($json.textBody || '')\n .split(/\\n\\s*\\n/)\n .filter(Boolean)\n .map(p => `<p>${escapeHtml(p).replace(/\\n/g, '<br>')}</p>`)\n .join('');\n\nconst htmlBody = `<div style=\"font-family:Arial,sans-serif;line-height:1.6;color:#222;max-width:600px;\">${paragraphs}<img src=\"${$json.trackingUrl}\" width=\"1\" height=\"1\" alt=\"\" style=\"display:block;border:0;width:1px;height:1px;\" /></div>`;\n\nreturn [{ json: { ...$json, htmlBody, sentAt: new Date().toISOString() } }];"
},
"typeVersion": 2
},
{
"id": "6312abdf-b288-4826-96bd-a0ee13be6b49",
"name": "Send via Gmail",
"type": "n8n-nodes-base.gmail",
"position": [
768,
-192
],
"parameters": {
"sendTo": "={{$json.toEmail}}",
"message": "={{$json.htmlBody}}",
"options": {
"appendAttribution": false
},
"subject": "={{$json.subject}}"
},
"credentials": {
"gmailOAuth2": {
"name": "<your credential>"
}
},
"typeVersion": 2.1
},
{
"id": "5b1cda78-237b-4e47-9dc1-a980b1db189d",
"name": "Date & Time",
"type": "n8n-nodes-base.dateTime",
"position": [
-192,
640
],
"parameters": {
"options": {}
},
"typeVersion": 2
},
{
"id": "32a3da49-c503-42cf-b95e-e83b27659976",
"name": "Sticky Note Overview",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1744,
-336
],
"parameters": {
"color": 5,
"width": 460,
"height": 272,
"content": "## Cold Email + Open Tracking\nThis workflow generates a personalized cold email from chat input, parses the AI output, creates a tracking URL, builds an HTML email, and sends it via Gmail.\n\nSecond branch: when the tracking pixel URL is loaded, the webhook captures the recipient metadata and sends you an internal open notification.\n\nNote: These sticky notes are documentation only and do not affect execution."
},
"typeVersion": 1
},
{
"id": "b80925e8-d07c-4501-a544-0b4553d90cfc",
"name": "Sticky - Chat Trigger",
"type": "n8n-nodes-base.stickyNote",
"position": [
-992,
-416
],
"parameters": {
"color": 7,
"width": 260,
"height": 410,
"content": "## Chat Trigger\nPaste your action, LinkedIn URL, company URL, website, job post, or plain text context here.\n\nThis starts the outreach flow and passes the user input to the AI Agent."
},
"typeVersion": 1
},
{
"id": "251eae44-d368-4bd3-b93a-c7de0d7ee3e3",
"name": "Sticky - Tracking Webhook",
"type": "n8n-nodes-base.stickyNote",
"position": [
-992,
416
],
"parameters": {
"color": 7,
"width": 300,
"height": 388,
"content": "## Tracking Webhook\nThis webhook is called when the tracking pixel URL is loaded from the recipient\u2019s email client.\n\nIt reads query parameters like email, name, and subject, then passes the event into the notification branch."
},
"typeVersion": 1
},
{
"id": "30fcbe91-3048-4957-a534-f1efc294dc74",
"name": "Sticky - Set Pixel Metadata",
"type": "n8n-nodes-base.stickyNote",
"position": [
-640,
448
],
"parameters": {
"color": 7,
"width": 320,
"height": 393,
"content": "## Set Pixel And Metadata\nThis node normalizes webhook data so the next nodes can use clean values.\n\nIt extracts tracked fields such as recipient email, recipient name, subject, and request IP header."
},
"typeVersion": 1
},
{
"id": "250d51a0-26ab-48b5-ba39-263d21e99923",
"name": "Sticky - Open Notification",
"type": "n8n-nodes-base.stickyNote",
"position": [
16,
448
],
"parameters": {
"color": 7,
"width": 280,
"height": 383,
"content": "## Open Notification\nThis Gmail node sends an internal alert when the tracking pixel is requested.\n\nUse it to monitor email opens with the recipient email, subject, and timestamp."
},
"typeVersion": 1
},
{
"id": "b61648f6-5ccb-41e8-8173-b5337f0728e9",
"name": "Sticky - AI Agent",
"type": "n8n-nodes-base.stickyNote",
"position": [
-672,
-416
],
"parameters": {
"color": 7,
"width": 310,
"height": 560,
"content": "## AI Agent\nThis node writes the personalized cold email based on the incoming context.\n\nIt is expected to return four labeled sections: Recipient Name, Email, Subject, and Email Body.\n\nIn prompt add your name"
},
"typeVersion": 1
},
{
"id": "4ee415dc-bfff-42bf-92e1-05ee04bf2562",
"name": "Sticky - Parse AI Output",
"type": "n8n-nodes-base.stickyNote",
"position": [
-288,
-448
],
"parameters": {
"color": 7,
"width": 264,
"height": 490,
"content": "## Parse AI Output\nThis node extracts structured fields from the AI response.\n\nIt expects predictable labels and throws an error if no recipient email is found."
},
"typeVersion": 1
},
{
"id": "c4bbe331-9538-40d3-8164-7bc961987420",
"name": "Sticky - Generate Tracking ID",
"type": "n8n-nodes-base.stickyNote",
"position": [
48,
-448
],
"parameters": {
"color": 7,
"width": 284,
"height": 484,
"content": "## Generate Tracking ID\nThis node creates a unique tracking ID and appends it to the tracking URL.\n\nReplace the placeholder webhook URL with your real production webhook URL before using the workflow."
},
"typeVersion": 1
},
{
"id": "e5617b86-61c3-4755-b16e-3a0def9f6def",
"name": "Sticky - Build HTML Email",
"type": "n8n-nodes-base.stickyNote",
"position": [
384,
-448
],
"parameters": {
"color": 7,
"width": 300,
"height": 474,
"content": "## Build HTML Email\nThis node converts the plain email body into HTML paragraphs and appends the tracking pixel image.\n\nThe output is used directly by the Gmail send node."
},
"typeVersion": 1
},
{
"id": "52da3d73-1b87-400e-9b21-53d4d3a6a714",
"name": "Sticky - Send via Gmail",
"type": "n8n-nodes-base.stickyNote",
"position": [
720,
-448
],
"parameters": {
"color": 7,
"width": 280,
"height": 447,
"content": "## Send via Gmail\nThis node sends the final personalized email to the extracted recipient email address.\n\nIt uses the subject from the AI output and the HTML body created in the previous step."
},
"typeVersion": 1
},
{
"id": "dbdd96df-4f58-419b-9b9c-5ee4f9c8604a",
"name": "Sticky - Date Time",
"type": "n8n-nodes-base.stickyNote",
"position": [
-272,
448
],
"parameters": {
"color": 7,
"width": 250,
"height": 389,
"content": "## Date & Time\nThis node adds the current timestamp to the webhook event.\n\nIt is used in the notification email so you know when the tracking pixel was loaded."
},
"typeVersion": 1
}
],
"active": false,
"settings": {
"binaryMode": "separate",
"executionOrder": "v1"
},
"versionId": "d6821c47-b90c-4b71-a690-f4fbdba75a60",
"nodeGroups": [],
"connections": {
"AI Agent": {
"main": [
[
{
"node": "Parse AI Output",
"type": "main",
"index": 0
}
]
]
},
"Date & Time": {
"main": [
[
{
"node": "Send Open Notification",
"type": "main",
"index": 0
}
]
]
},
"Parse AI Output": {
"main": [
[
{
"node": "Generate Tracking ID",
"type": "main",
"index": 0
}
]
]
},
"Build HTML Email": {
"main": [
[
{
"node": "Send via Gmail",
"type": "main",
"index": 0
}
]
]
},
"Tracking Webhook": {
"main": [
[
{
"node": "Set Pixel And Metadata",
"type": "main",
"index": 0
}
]
]
},
"Generate Tracking ID": {
"main": [
[
{
"node": "Build HTML Email",
"type": "main",
"index": 0
}
]
]
},
"Set Pixel And Metadata": {
"main": [
[
{
"node": "Date & Time",
"type": "main",
"index": 0
}
]
]
},
"Google Gemini Chat Model": {
"ai_languageModel": [
[
{
"node": "AI Agent",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"When chat message received": {
"main": [
[
{
"node": "AI Agent",
"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.
gmailOAuth2googlePalmApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This workflow uses an n8n Chat trigger with Google Gemini to draft a personalized cold email, sends it via Gmail with a tracking pixel, and then captures opens through a webhook that triggers an internal Gmail notification. Receives a chat message in n8n containing an action and…
Source: https://n8n.io/workflows/16249/ — 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.
Enhance your support, onboarding, and internal knowledge workflows with an intelligent RAG-powered chatbot that responds using live data stored in Google Sheets. 🤖📚 Built for teams that rely on struct
leads. Uses supabase, gmail, formTrigger, httpRequest. Webhook trigger; 62 nodes.
Catat Keuangan Keluarga. Uses chatTrigger, agent, lmChatGoogleGemini, outputParserStructured. Webhook trigger; 55 nodes.
This workflow implements an AI-powered WhatsApp booking assistant for a hair salon. The system allows customers to book, reschedule, or cancel appointments automatically via text or voice messages on
updated!. Uses lmChatGoogleGemini, agent, memoryBufferWindow, httpRequest. Webhook trigger; 40 nodes.