8
n8n 한국어amn8n.com

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
워크플로우 미리보기
노드 연결 관계를 시각적으로 표시하며, 확대/축소 및 이동을 지원합니다
워크플로우 내보내기
다음 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)는 사용자 직접 비용을 지불해야 할 수 있습니다.

워크플로우 정보
난이도
고급
노드 수16
카테고리2
노드 유형10
난이도 설명

고급 사용자를 위한 16+개 노드의 복잡한 워크플로우

외부 링크
n8n.io에서 보기

이 워크플로우 공유

카테고리

카테고리: 34