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": "Send scheduled n8n release notes notifications to 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 Chat Model",
"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": "Structured Output Parser",
"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": "Schedule Trigger",
"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": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-688,
-352
],
"parameters": {
"width": 368,
"height": 528,
"content": "## n8n Release Notifications Workflow\n\n**Stay updated with the latest n8n releases automatically!**\n\n## What this workflow does:\n- Runs on a schedule (configurable)\n- Fetches latest release notes from n8n GitHub\n- Uses AI to summarize key features and bug fixes\n- Sends formatted email notifications via Gmail\n\n## Setup required:\n1. **Schedule Trigger** - Adjust frequency if needed\n2. **OpenAI credentials** - Add your API key or connect different LLM\n3. **Gmail credentials** - Connect your Google account\n4. **Recipient email** - Set the \"To\" address in the Gmail node"
},
"typeVersion": 1
},
{
"id": "be26a459-0049-46a8-b4a7-4efd9549a30c",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-296,
-128
],
"parameters": {
"color": 7,
"width": 176,
"height": 304,
"content": "### 1. Schedule Trigger\n\nSet your preferred frequency."
},
"typeVersion": 1
},
{
"id": "1baae255-a154-46bd-af66-fdaed8ad6d95",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
-88,
-224
],
"parameters": {
"color": 7,
"width": 656,
"height": 400,
"content": "### 2. Get n8n release notes and filter\n\n- Get all release notes\n- Filters releases based on timeframe\n- Formats data\n\nNo configuration needed - it's automatic!"
},
"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": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
608,
-272
],
"parameters": {
"color": 7,
"width": 288,
"height": 640,
"content": "### AI Summarization\n\nOpenAI analyzes release notes and extracts:\n- Important bug fixes\n- New features\n\n**⚠️Setup Required:**\nAdd your OpenAI API credentials here or connect a different LLM provider."
},
"typeVersion": 1
},
{
"id": "7d414dfc-9171-4bf2-9e79-64f9e52b637e",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
960,
-144
],
"parameters": {
"color": 7,
"width": 384,
"height": 304,
"content": "### Format for Email\n\nBuild an HTML template for email."
},
"typeVersion": 1
},
{
"id": "f1260b97-38b0-4791-baa4-08a4a4aad868",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
1392,
-224
],
"parameters": {
"color": 7,
"height": 384,
"content": "### Send Email\n\nSend via Gmail.\n\n**⚠️ Setup Required:**\n1. Add Gmail credentials\n2. Set recipient email address in the \"To\" field"
},
"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": {
"d60758f6-313d-4d95-a5a4-6f22df51f4d0": {
"main": [
[
{
"node": "796aa3f1-6f22-4583-b6cc-ace9616c3fe1",
"type": "main",
"index": 0
}
]
]
},
"d3d79b32-6405-405a-864a-4953f824ca6b": {
"main": [
[
{
"node": "9f097a51-1167-4c61-a17d-8c574140c0bd",
"type": "main",
"index": 0
}
]
]
},
"09d6bcf3-9cf2-40da-83b5-89833fe663d6": {
"ai_languageModel": [
[
{
"node": "4d8a12ea-5ae3-4e4a-9e93-df5dc53cdb06",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"9f097a51-1167-4c61-a17d-8c574140c0bd": {
"main": [
[
{
"node": "7a1ec69a-dc91-4365-9686-9d0b2a361736",
"type": "main",
"index": 0
}
]
]
},
"796aa3f1-6f22-4583-b6cc-ace9616c3fe1": {
"main": [
[
{
"node": "fafd7a5e-0e9a-49ec-b097-6019d068c1cd",
"type": "main",
"index": 0
}
]
]
},
"7a1ec69a-dc91-4365-9686-9d0b2a361736": {
"main": [
[
{
"node": "160368b0-4fcd-4eca-b478-4154d9aa35c9",
"type": "main",
"index": 0
}
]
]
},
"a3e60adf-ed32-4f6b-9903-39094c5697d3": {
"ai_outputParser": [
[
{
"node": "4d8a12ea-5ae3-4e4a-9e93-df5dc53cdb06",
"type": "ai_outputParser",
"index": 0
}
]
]
},
"4d8a12ea-5ae3-4e4a-9e93-df5dc53cdb06": {
"main": [
[
{
"node": "d60758f6-313d-4d95-a5a4-6f22df51f4d0",
"type": "main",
"index": 0
}
]
]
},
"160368b0-4fcd-4eca-b478-4154d9aa35c9": {
"main": [
[
{
"node": "4d8a12ea-5ae3-4e4a-9e93-df5dc53cdb06",
"type": "main",
"index": 0
}
]
]
}
}
}자주 묻는 질문
이 워크플로우를 어떻게 사용하나요?
위의 JSON 구성 코드를 복사하여 n8n 인스턴스에서 새 워크플로우를 생성하고 "JSON에서 가져오기"를 선택한 후, 구성을 붙여넣고 필요에 따라 인증 설정을 수정하세요.
이 워크플로우는 어떤 시나리오에 적합한가요?
고급 - 개인 생산성, AI 요약
유료인가요?
이 워크플로우는 완전히 무료이며 직접 가져와 사용할 수 있습니다. 다만, 워크플로우에서 사용하는 타사 서비스(예: OpenAI API)는 사용자 직접 비용을 지불해야 할 수 있습니다.
관련 워크플로우 추천
Mistral AI, LinkedIn 및 Google Sheets를 사용한 구직 활동 및 이력서 맞춤화 자동화
Mistral AI, LinkedIn 및 Google Sheets를 사용한 채용 공고 검색 및 이력서 맞춤화 자동화
Set
Code
Html
+
Set
Code
Html
46 노드Jordan Hoyle
개인 생산성
LinkedIn 직업 검색
LinkedIn 직업 검색: 자동 이력서 매칭(GPT/Gemini) + 취업서생성기 + Telegram 알림
If
Set
Code
+
If
Set
Code
33 노드Hojjat Jashnniloofar
개인 생산성
AI Gmail: 읽어야 할 메일 우선순위 지정
Gmail과 GPT-4o를 활용한 자동 이메일 분류 및 라벨링
Set
Gmail
Switch
+
Set
Gmail
Switch
17 노드Matt Chong
개인 생산성
시각화 참조 라이브러리에서 n8n 노드를 탐색
可视化 참조 라이브러리에서 n8n 노드를 탐색
If
Ftp
Set
+
If
Ftp
Set
113 노드I versus AI
기타
🗞️ AI로운 지속 가능한 마케팅 브리핑(gmail, GPT-4o 사용)
🗞️ AI 주도의 지속 가능성 마케팅 브리핑( Gmail, GPT-4o 사용)
If
Set
Code
+
If
Set
Code
21 노드Samir Saci
인공지능
사용Slack및Asana의虚拟Scrum Master
基于AI의Scrum Master어시스턴트,통합OpenAI、Slack및Asana
Set
Code
Html
+
Set
Code
Html
35 노드Łukasz
프로젝트 관리