发送定时n8n发布说明通知到Gmail
高级
这是一个Personal Productivity, AI Summarization领域的自动化工作流,包含 16 个节点。主要使用 Set, Code, Html, Gmail, HttpRequest 等节点。 基于AI的n8n发布说明摘要通知(通过Gmail与GPT-5-Mini)
前置要求
- •Google 账号和 Gmail API 凭证
- •可能需要目标 API 的认证凭证
- •OpenAI API Key
使用的节点 (16)
工作流预览
可视化展示节点连接关系,支持缩放和平移
导出工作流
复制以下 JSON 配置到 n8n 导入,即可使用此工作流
{
"id": "z301sXBDAZd8EDCw",
"meta": {
"instanceId": "2e134e0f94da86d43329d3d8d3284f5c8c835c03cb84be5ca46f772b2cf7a103",
"templateCredsSetupCompleted": true
},
"name": "发送定时 n8n 发布说明通知到 Gmail",
"tags": [
{
"id": "W3G9QjFn5zCWN18M",
"name": "Notifications",
"createdAt": "2025-10-27T20:32:25.385Z",
"updatedAt": "2025-10-27T20:32:25.385Z"
},
{
"id": "dF0HqEuaD5GnFCI0",
"name": "n8n",
"createdAt": "2025-10-27T20:32:30.037Z",
"updatedAt": "2025-10-27T20:32:30.037Z"
},
{
"id": "CF6Q37w8HHllwE7l",
"name": "gmail",
"createdAt": "2025-10-27T20:32:34.939Z",
"updatedAt": "2025-10-27T20:32:34.939Z"
}
],
"nodes": [
{
"id": "09d6bcf3-9cf2-40da-83b5-89833fe663d6",
"name": "OpenAI 聊天模型",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
648,
224
],
"parameters": {
"model": {
"__rl": true,
"mode": "list",
"value": "gpt-5-mini",
"cachedResultName": "gpt-5-mini"
},
"options": {}
},
"typeVersion": 1.2
},
{
"id": "a3e60adf-ed32-4f6b-9903-39094c5697d3",
"name": "结构化输出解析器",
"type": "@n8n/n8n-nodes-langchain.outputParserStructured",
"position": [
776,
224
],
"parameters": {
"jsonSchemaExample": "{\n\t\"releaseBugFixes\": [\"\"],\n\t\"releaseFeatures\": [\"\"]\n}"
},
"typeVersion": 1.3
},
{
"id": "d3d79b32-6405-405a-864a-4953f824ca6b",
"name": "定时触发器",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
-256,
0
],
"parameters": {
"rule": {
"interval": [
{
"triggerAtHour": 8
}
]
}
},
"executeOnce": false,
"notesInFlow": false,
"typeVersion": 1.2,
"alwaysOutputData": false
},
{
"id": "7a1ec69a-dc91-4365-9686-9d0b2a361736",
"name": "提取更新内容的 HTML",
"type": "n8n-nodes-base.html",
"position": [
192,
0
],
"parameters": {
"options": {},
"operation": "extractHtmlContent",
"extractionValues": {
"values": [
{
"key": "sections",
"cssSelector": "section",
"returnArray": true,
"returnValue": "html"
}
]
}
},
"typeVersion": 1.2
},
{
"id": "160368b0-4fcd-4eca-b478-4154d9aa35c9",
"name": "格式化数据并根据触发器筛选",
"type": "n8n-nodes-base.code",
"position": [
416,
0
],
"parameters": {
"jsCode": "const cheerio = require('cheerio');\n\n// Get the array of section HTML strings\nconst allSections = $input.first().json.sections;\n\n// Get schedule trigger configuration\nconst scheduleParams = $(\"Schedule Trigger\").params;\nlet checkWindowHours = 24; // Default fallback\n\n// Calculate the time window based on schedule trigger settings\nif (scheduleParams?.rule?.interval?.[0]) {\n const interval = scheduleParams.rule.interval[0];\n const field = interval.field;\n \n if (field === 'days' && interval.daysInterval) {\n checkWindowHours = interval.daysInterval * 24;\n } else if (field === 'hours' && interval.hoursInterval) {\n checkWindowHours = interval.hoursInterval;\n } else if (field === 'minutes' && interval.minutesInterval) {\n checkWindowHours = (interval.minutesInterval / 60);\n } else if (field === 'seconds' && interval.secondsInterval) {\n checkWindowHours = (interval.secondsInterval / 3600);\n } else if (field === 'weeks' && interval.weeksInterval) {\n checkWindowHours = interval.weeksInterval * 7 * 24;\n } else if (field === 'months' && interval.monthsInterval) {\n checkWindowHours = interval.monthsInterval * 30 * 24;\n }\n}\n\nconsole.log(`Using time window of ${checkWindowHours} hours based on schedule trigger`);\n\n// Get current date/time\nconst now = DateTime.now();\n\nconst results = [];\n\n// Process each section HTML string\nallSections.forEach((sectionHtml, index) => {\n // Load this section's HTML with cheerio\n const $ = cheerio.load(sectionHtml);\n \n // Get the relative time element's datetime attribute\n const relativeTime = $('relative-time');\n if (relativeTime.length === 0) return;\n \n const dateTimeAttr = relativeTime.attr('datetime');\n if (!dateTimeAttr) return;\n \n // Parse the ISO datetime (format: \"2025-10-27T12:23:36Z\")\n const releaseDateTime = DateTime.fromISO(dateTimeAttr);\n \n if (!releaseDateTime.isValid) {\n console.log(`Failed to parse datetime: ${dateTimeAttr}`);\n return;\n }\n \n // Check if within the dynamic time window based on schedule trigger\n const diffInHours = now.diff(releaseDateTime, 'hours').hours;\n if (diffInHours > checkWindowHours || diffInHours < 0) return;\n \n // Extract releaseVersion from first h2\n const firstH2 = $('h2').first();\n const releaseVersion = firstH2.text().trim();\n \n // Format releaseDate\n const releaseDate = releaseDateTime.toFormat('d MMMM, yyyy HH:mm');\n \n // Extract releaseLink from div.markdown-body > h2 > a\n const markdownBody = $('div.markdown-body');\n \n const releaseLink2 = $('div.flex-1 span.f1 a.Link--primary').attr('href') || '';\n const releaseLink = releaseLink2 ? ('https://github.com/'+releaseLink2) :''\n \n // Extract bug fixes and features\n let releaseBugFixes = [];\n let releaseFeatures = [];\n \n if (markdownBody.length > 0) {\n markdownBody.find('h3').each((i, h3Element) => {\n const h3 = $(h3Element);\n const h3Text = h3.text().trim();\n \n // Find Bug Fixes\n if (h3Text === 'Bug Fixes' || h3Text.includes('Bug Fix')) {\n let nextEl = h3.next();\n // Look for next ul, but stop at next heading\n while (nextEl.length > 0 && !nextEl.is('ul')) {\n if (nextEl.is('h2, h3')) break;\n nextEl = nextEl.next();\n }\n if (nextEl.is('ul')) {\n nextEl.find('li').each((j, li) => {\n releaseBugFixes.push($(li).text().trim());\n });\n }\n }\n \n // Find Features\n if (h3Text === 'Features' || h3Text.includes('Feature')) {\n let nextEl = h3.next();\n // Look for next ul, but stop at next heading\n while (nextEl.length > 0 && !nextEl.is('ul')) {\n if (nextEl.is('h2, h3')) break;\n nextEl = nextEl.next();\n }\n if (nextEl.is('ul')) {\n nextEl.find('li').each((j, li) => {\n releaseFeatures.push($(li).text().trim());\n });\n }\n }\n });\n }\n \n results.push({\n releaseVersion,\n releaseDate,\n releaseLink,\n releaseBugFixes,\n releaseFeatures\n });\n});\n\n// Return results in n8n format\nreturn results.map(item => ({ json: item }));"
},
"typeVersion": 2
},
{
"id": "d60758f6-313d-4d95-a5a4-6f22df51f4d0",
"name": "格式化数据",
"type": "n8n-nodes-base.set",
"position": [
992,
0
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "38260412-2d4d-4f9e-ab33-1839ea1e5b6a",
"name": "releaseVersion",
"type": "string",
"value": "={{ $('Format Data and Filter based on Trigger').item.json.releaseVersion }}"
},
{
"id": "601016bd-9724-4608-bd41-cd4127c21268",
"name": "releaseDate",
"type": "string",
"value": "={{ $('Format Data and Filter based on Trigger').item.json.releaseDate }}"
},
{
"id": "70fdeddb-fd07-439c-8ec8-a2b7b9bfc1d4",
"name": "releaseLink",
"type": "string",
"value": "={{ $('Format Data and Filter based on Trigger').item.json.releaseLink }}"
},
{
"id": "dda79d93-e36a-40b2-9874-5564f6d4336f",
"name": "output.releaseFeatures",
"type": "array",
"value": "={{ $json.output.releaseFeatures }}"
},
{
"id": "ae95cbf9-531e-4a3b-8d59-cb5162209d03",
"name": "output.releaseBugFixes",
"type": "array",
"value": "={{ $json.output.releaseBugFixes }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "796aa3f1-6f22-4583-b6cc-ace9616c3fe1",
"name": "生成 HTML 模板",
"type": "n8n-nodes-base.code",
"position": [
1216,
0
],
"parameters": {
"jsCode": "// Get the input data\nconst items = $input.all();\n\n// Start building the HTML\nlet html = `\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>n8n Daily Update</title>\n <style>\n body {\n font-family: Arial, sans-serif;\n line-height: 1.6;\n color: #333;\n max-width: 800px;\n margin: 0 auto;\n padding: 20px;\n background-color: #f4f4f4;\n }\n .container {\n background-color: #ffffff;\n border-radius: 8px;\n padding: 30px;\n box-shadow: 0 2px 4px rgba(0,0,0,0.1);\n }\n .header {\n text-align: center;\n border-bottom: 3px solid #d62854;\n padding-bottom: 20px;\n margin-bottom: 30px;\n }\n .header h1 {\n color: #d62854;\n margin: 0;\n font-size: 28px;\n }\n .header p {\n color: #666;\n margin: 10px 0 0 0;\n }\n .release {\n margin-bottom: 40px;\n border-left: 4px solid #d62854;\n padding-left: 20px;\n }\n .release-header {\n margin-bottom: 15px;\n }\n .release-version {\n font-size: 22px;\n font-weight: bold;\n color: #333;\n margin: 0 0 5px 0;\n }\n .release-date {\n color: #666;\n font-size: 14px;\n margin: 0 0 10px 0;\n }\n .release-link {\n display: inline-block;\n color: #d62854;\n text-decoration: none;\n font-size: 14px;\n font-weight: 500;\n }\n .release-link:hover {\n text-decoration: underline;\n }\n .section {\n margin-top: 20px;\n }\n .section-title {\n font-size: 16px;\n font-weight: bold;\n color: #d62854;\n margin-bottom: 10px;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n }\n .items-list {\n margin: 0;\n padding-left: 20px;\n }\n .items-list li {\n margin-bottom: 10px;\n color: #555;\n }\n .no-items {\n color: #999;\n font-style: italic;\n }\n .footer {\n text-align: center;\n margin-top: 40px;\n padding-top: 20px;\n border-top: 1px solid #ddd;\n color: #666;\n font-size: 12px;\n }\n </style>\n</head>\n<body>\n <div class=\"container\">\n <div class=\"header\">\n <h1>🚀 n8n Updates</h1>\n <p>Latest releases, features, and bug fixes</p>\n </div>\n`;\n\n// Loop through each release\nitems.forEach((item) => {\n const data = item.json;\n const version = data.releaseVersion || 'Unknown Version';\n const date = data.releaseDate || 'Unknown Date';\n const link = data.releaseLink || '#';\n const features = data.output?.releaseFeatures || [];\n const bugFixes = data.output?.releaseBugFixes || [];\n\n html += `\n <div class=\"release\">\n <div class=\"release-header\">\n <h2 class=\"release-version\">${version}</h2>\n <p class=\"release-date\">📅 ${date}</p>\n <a href=\"${link}\" class=\"release-link\" target=\"_blank\">View on GitHub →</a>\n </div>\n `;\n\n // Add Features section\n html += `<div class=\"section\"><div class=\"section-title\">🎉 New Features</div>`;\n \n if (features.length > 0) {\n html += `<ul class=\"items-list\">`;\n features.forEach(feature => {\n html += `<li>${feature}</li>`;\n });\n html += `</ul>`;\n } else {\n html += `<p class=\"no-items\">No new features in this release</p>`;\n }\n html += `</div>`;\n\n // Add Bug Fixes section\n html += `<div class=\"section\"><div class=\"section-title\">🔧 Bug Fixes</div>`;\n \n if (bugFixes.length > 0) {\n html += `<ul class=\"items-list\">`;\n bugFixes.forEach(fix => {\n html += `<li>${fix}</li>`;\n });\n html += `</ul>`;\n } else {\n html += `<p class=\"no-items\">No bug fixes in this release</p>`;\n }\n html += `</div></div>`;\n});\n\n// Return the HTML\nreturn [{ json: { html } }];"
},
"typeVersion": 2
},
{
"id": "4d8a12ea-5ae3-4e4a-9e93-df5dc53cdb06",
"name": "汇总 n8n 更新数据",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
640,
0
],
"parameters": {
"text": "=Give me a summary of the Release Bug Fixes and Release Features as a list of important releases. Include only the important ones, and summarize as much as possible. Use simple language.\n\n{releaseBugFixes: {{ $json.releaseBugFixes }},\nreleaseFeatures: {{ $json.releaseFeatures }}\n} ",
"options": {
"maxIterations": 3
},
"promptType": "define",
"hasOutputParser": true
},
"typeVersion": 3
},
{
"id": "12e67c90-bc13-458d-a45b-14ab5881d31c",
"name": "便签",
"type": "n8n-nodes-base.stickyNote",
"position": [
-688,
-352
],
"parameters": {
"width": 368,
"height": 528,
"content": "## n8n 发布通知工作流"
},
"typeVersion": 1
},
{
"id": "be26a459-0049-46a8-b4a7-4efd9549a30c",
"name": "便签1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-296,
-128
],
"parameters": {
"color": 7,
"width": 176,
"height": 304,
"content": "### 1. 定时触发器"
},
"typeVersion": 1
},
{
"id": "1baae255-a154-46bd-af66-fdaed8ad6d95",
"name": "便签2",
"type": "n8n-nodes-base.stickyNote",
"position": [
-88,
-224
],
"parameters": {
"color": 7,
"width": 656,
"height": 400,
"content": "### 2. 获取 n8n 发布说明并筛选"
},
"typeVersion": 1
},
{
"id": "9f097a51-1167-4c61-a17d-8c574140c0bd",
"name": "获取 n8n 发布说明",
"type": "n8n-nodes-base.httpRequest",
"position": [
-32,
0
],
"parameters": {
"url": "https://github.com/n8n-io/n8n/releases",
"options": {}
},
"typeVersion": 4.2
},
{
"id": "a9dcc608-56f9-4e94-ab8a-2401c1675484",
"name": "便签3",
"type": "n8n-nodes-base.stickyNote",
"position": [
608,
-272
],
"parameters": {
"color": 7,
"width": 288,
"height": 640,
"content": "### AI 摘要生成"
},
"typeVersion": 1
},
{
"id": "7d414dfc-9171-4bf2-9e79-64f9e52b637e",
"name": "便签4",
"type": "n8n-nodes-base.stickyNote",
"position": [
960,
-144
],
"parameters": {
"color": 7,
"width": 384,
"height": 304,
"content": "### 邮件格式化"
},
"typeVersion": 1
},
{
"id": "f1260b97-38b0-4791-baa4-08a4a4aad868",
"name": "便签5",
"type": "n8n-nodes-base.stickyNote",
"position": [
1392,
-224
],
"parameters": {
"color": 7,
"height": 384,
"content": "### 发送邮件"
},
"typeVersion": 1
},
{
"id": "fafd7a5e-0e9a-49ec-b097-6019d068c1cd",
"name": "发送消息",
"type": "n8n-nodes-base.gmail",
"position": [
1456,
0
],
"webhookId": "405dc9ef-79d6-493a-963f-08ecead7bd06",
"parameters": {
"message": "={{ $json.html }}",
"options": {
"appendAttribution": false
},
"subject": "=n8n Updates - {{ $now.format('DDD') }}"
},
"typeVersion": 2.1
}
],
"active": false,
"pinData": {},
"settings": {
"executionOrder": "v1"
},
"versionId": "0f73b185-10b8-4ab7-87a8-c441fd924d13",
"connections": {
"Format Data": {
"main": [
[
{
"node": "Generate HTML template",
"type": "main",
"index": 0
}
]
]
},
"Schedule Trigger": {
"main": [
[
{
"node": "Get n8n release notes",
"type": "main",
"index": 0
}
]
]
},
"OpenAI Chat Model": {
"ai_languageModel": [
[
{
"node": "Summarize n8n Update Data",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Get n8n release notes": {
"main": [
[
{
"node": "Extract HTML for updates",
"type": "main",
"index": 0
}
]
]
},
"Generate HTML template": {
"main": [
[
{
"node": "Send a message",
"type": "main",
"index": 0
}
]
]
},
"Extract HTML for updates": {
"main": [
[
{
"node": "Format Data and Filter based on Trigger",
"type": "main",
"index": 0
}
]
]
},
"Structured Output Parser": {
"ai_outputParser": [
[
{
"node": "Summarize n8n Update Data",
"type": "ai_outputParser",
"index": 0
}
]
]
},
"Summarize n8n Update Data": {
"main": [
[
{
"node": "Format Data",
"type": "main",
"index": 0
}
]
]
},
"Format Data and Filter based on Trigger": {
"main": [
[
{
"node": "Summarize n8n Update Data",
"type": "main",
"index": 0
}
]
]
}
}
}常见问题
如何使用这个工作流?
复制上方的 JSON 配置代码,在您的 n8n 实例中创建新工作流并选择「从 JSON 导入」,粘贴配置后根据需要修改凭证设置即可。
这个工作流适合什么场景?
高级 - 个人效率, AI 摘要总结
需要付费吗?
本工作流完全免费,您可以直接导入使用。但请注意,工作流中使用的第三方服务(如 OpenAI API)可能需要您自行付费。
相关工作流推荐
使用 Mistral AI、LinkedIn 和 Google Sheets 自动化职位搜索与简历定制
使用 Mistral AI、LinkedIn 和 Google Sheets 自动化职位搜索与简历定制
Set
Code
Html
+18
46 节点Jordan Hoyle
个人效率
LinkedIn职位搜索
LinkedIn职位搜索:自动匹配简历(GPT/Gemini)+求职信生成器+Telegram提醒
If
Set
Code
+13
33 节点Hojjat Jashnniloofar
个人效率
新抓取器_TechCrunch新闻-AI1
TechCrunch AI文章抓取与分类器,使用GPT-4.1-nano到Sheets和Telegram
Set
Code
Html
+12
18 节点Mujahid Kabae
市场调研
AI Gmail:优先处理您应阅读的内容
使用Gmail和GPT-4o自动分类和标记邮件
Set
Gmail
Switch
+5
17 节点Matt Chong
个人效率
在可视化参考库中探索n8n节点
在可视化参考库中探索n8n节点
If
Ftp
Set
+93
113 节点I versus AI
其他
🗞️ AI驱动的可持续性营销简报(使用Gmail、GPT-4o)
🗞️ AI驱动的可持续性营销简报(使用Gmail、GPT-4o)
If
Set
Code
+12
21 节点Samir Saci
人工智能