Envío de notificaciones programadas de n8n a Gmail

Avanzado

Este es unPersonal Productivity, AI Summarizationflujo de automatización del dominio deautomatización que contiene 16 nodos.Utiliza principalmente nodos como Set, Code, Html, Gmail, HttpRequest. Resumen y notificación de notas de versión para n8n basado en AI (a través de Gmail y GPT-5-Mini)

Requisitos previos
  • Cuenta de Google y credenciales de API de Gmail
  • Pueden requerirse credenciales de autenticación para la API de destino
  • Clave de API de OpenAI
Vista previa del flujo de trabajo
Visualización de las conexiones entre nodos, con soporte para zoom y panorámica
Exportar flujo de trabajo
Copie la siguiente configuración JSON en n8n para importar y usar este flujo de trabajo
{
  "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": "Modelo de chat 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": "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": "Disparador programado",
      "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": "Extract HTML for updates",
      "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": "Format Data and Filtrar based on Trigger",
      "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": "Format Data",
      "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": "Generate HTML template",
      "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": "Resumir n8n Update Data",
      "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": "Nota adhesiva",
      "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": "Nota adhesiva1",
      "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": "Nota adhesiva2",
      "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": "Get n8n release notes",
      "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": "Nota adhesiva3",
      "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": "Nota adhesiva4",
      "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": "Nota adhesiva5",
      "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": "Send a message",
      "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
          }
        ]
      ]
    },
    "Schedule Trigger": {
      "main": [
        [
          {
            "node": "9f097a51-1167-4c61-a17d-8c574140c0bd",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "Summarize n8n Update Data",
            "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": "Format Data and Filter based on Trigger",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "a3e60adf-ed32-4f6b-9903-39094c5697d3": {
      "ai_outputParser": [
        [
          {
            "node": "Summarize n8n Update Data",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "Summarize n8n Update Data": {
      "main": [
        [
          {
            "node": "d60758f6-313d-4d95-a5a4-6f22df51f4d0",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format Data and Filter based on Trigger": {
      "main": [
        [
          {
            "node": "Summarize n8n Update Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
Preguntas frecuentes

¿Cómo usar este flujo de trabajo?

Copie el código de configuración JSON de arriba, cree un nuevo flujo de trabajo en su instancia de n8n y seleccione "Importar desde JSON", pegue la configuración y luego modifique la configuración de credenciales según sea necesario.

¿En qué escenarios es adecuado este flujo de trabajo?

Avanzado - Productividad personal, Resumen de IA

¿Es de pago?

Este flujo de trabajo es completamente gratuito, puede importarlo y usarlo directamente. Sin embargo, tenga en cuenta que los servicios de terceros utilizados en el flujo de trabajo (como la API de OpenAI) pueden requerir un pago por su cuenta.

Información del flujo de trabajo
Nivel de dificultad
Avanzado
Número de nodos16
Categoría2
Tipos de nodos10
Descripción de la dificultad

Adecuado para usuarios avanzados, flujos de trabajo complejos con 16+ nodos

Enlaces externos
Ver en n8n.io

Compartir este flujo de trabajo

Categorías

Categorías: 34