Correo electrónico → Correo electrónico público

Intermedio

Este es unPersonal Productivity, Multimodal AIflujo de automatización del dominio deautomatización que contiene 13 nodos.Utiliza principalmente nodos como Code, Gmail, SplitInBatches, ScheduleTrigger, OpenAi. Usar GPT-4.1-mini para crear resúmenes de boletines de noticias diarios a partir de Gmail

Requisitos previos
  • Cuenta de Google y credenciales de API de Gmail
  • 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": "4LGHvpa2PjTNwGc1",
  "meta": {
    "instanceId": "93438a4980e64a583ea2325b4dc5eae4c4c531c30461a48c79a4b262b5c53893",
    "templateCredsSetupCompleted": true
  },
  "name": "email → email public",
  "tags": [
    {
      "id": "TIMIlK5hNxVuDAlg",
      "name": "public",
      "createdAt": "2025-08-11T13:46:00.810Z",
      "updatedAt": "2025-08-11T13:46:00.810Z"
    }
  ],
  "nodes": [
    {
      "id": "8636c298-0e5a-494d-9bd1-beace2be380c",
      "name": "Obtener muchos mensajes",
      "type": "n8n-nodes-base.gmail",
      "position": [
        368,
        64
      ],
      "webhookId": "e1b897aa-1e4d-4880-8be0-df0c5f5d577c",
      "parameters": {
        "filters": {
          "q": "=(from:____@____.com) OR (from:____@____.com) OR (from:____@____.com -\"____\") after:{{ $now.minus({ days: 1 }).toFormat('yyyy/MM/dd') }}"
        },
        "operation": "getAll",
        "returnAll": true
      },
      "credentials": {
        "gmailOAuth2": {
          "id": "sqe7HFlBnGaSLwH9",
          "name": "Gmail account"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "d77aad78-85fa-4dd1-9227-6636b023dc04",
      "name": "Iterar sobre elementos",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        592,
        64
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "3f688cd5-ac4b-4965-a9d4-2220cee11440",
      "name": "Obtener un mensaje",
      "type": "n8n-nodes-base.gmail",
      "position": [
        816,
        64
      ],
      "webhookId": "309187bc-88e5-4174-8aea-e3be7dc0b20e",
      "parameters": {
        "simple": false,
        "options": {},
        "messageId": "={{ $json.id }}",
        "operation": "get"
      },
      "credentials": {
        "gmailOAuth2": {
          "id": "sqe7HFlBnGaSLwH9",
          "name": "Gmail account"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "104254b9-51ea-4655-9e49-38dd3b200929",
      "name": "Obtener datos del mensaje",
      "type": "n8n-nodes-base.code",
      "position": [
        1040,
        64
      ],
      "parameters": {
        "jsCode": "function extractHtml(payload) {\n  if (!payload) return '';\n  if (payload.body && payload.body.data) {\n    return Buffer.from(payload.body.data, 'base64').toString('utf-8');\n  }\n  function findHtmlPart(parts) {\n    for (const part of parts) {\n      if (part.mimeType === 'text/html' && part.body && part.body.data) {\n        return Buffer.from(part.body.data, 'base64').toString('utf-8');\n      }\n      if (part.parts) {\n        const result = findHtmlPart(part.parts);\n        if (result) return result;\n      }\n    }\n    return '';\n  }\n  if (payload.parts) {\n    const html = findHtmlPart(payload.parts);\n    if (html) return html;\n  }\n  return '';\n}\n\nlet html = $json.html || '';\nif (!html && $json.payload) {\n  html = extractHtml($json.payload);\n}\nif (!html && $json.text) {\n  html = $json.text;\n}\n\n// Clean 'from': keep only the sender's name\nlet from = $json.from?.text || $json.from || '';\nconst match = from.match(/^\\\"?([^\\\"<]+)\\\"?\\s*<[^>]+>$/);\nif (match) {\n  from = match[1].trim();\n}\n\n// Convert date to DD.MM.YYYY format\nlet date = $json.date || '';\nlet formattedDate = date;\nif (date) {\n  const d = new Date(date);\n  const day = String(d.getDate()).padStart(2, '0');\n  const month = String(d.getMonth() + 1).padStart(2, '0');\n  const year = d.getFullYear();\n  formattedDate = `${day}.${month}.${year}`;\n}\n\nconst subject = $json.subject || '';\n\nreturn [{\n  html,\n  subject,\n  from,\n  date: formattedDate\n}];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "31e5402b-7146-4955-ae7b-ee4dd3ecc583",
      "name": "Combinar",
      "type": "n8n-nodes-base.code",
      "position": [
        816,
        -128
      ],
      "parameters": {
        "jsCode": "/**\n * This code is intended for use in the \"Code\" node in n8n.\n * It merges the 'topics' arrays from several incoming items into a single array.\n *\n * Incoming data (items) have the following structure:\n * [\n * { json: { message: { content: { topics: [...] } } } },\n * { json: { message: { content: { topics: [...] } } } },\n * ...\n * ]\n */\n\n// We use the flatMap method, which is a combination of map and flat.\n// It iterates over each element (item) in the incoming array (items),\n// extracts the 'topics' array and immediately flattens all collected arrays into one.\nconst allTopics = items.flatMap(item => {\n  // We use optional chaining (?.) for safe access to the nested property.\n  // This prevents an error if 'message' or 'content' is missing in any element.\n  // If the path is not found, return an empty array [] so flatMap can work correctly.\n  return item.json?.message?.content?.topics || [];\n});\n\n// The \"Code\" node must return an array of objects.\n// We return one object containing the 'json' property with our merged 'topics' array.\n// This result will be available on the node's output for further use.\nreturn [{\n  json: {\n    topics: allTopics\n  }\n}];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "df46e906-1a21-47c3-9168-900ee58c3730",
      "name": "Limpiar",
      "type": "n8n-nodes-base.code",
      "position": [
        1264,
        64
      ],
      "parameters": {
        "jsCode": "/**\n * This code is intended for use in the \"Code\" node in n8n.\n * Its task is to prepare data from the Gmail node for the next node (LLM).\n * It does not parse HTML; it only passes it along with other fields.\n *\n * Incoming data (items) — this is the result of the Gmail node.\n * [\n * { json: { html: \"...\", subject: \"...\", from: \"...\", date: \"DD.MM.YYYY\" } }\n * ]\n *\n * The code converts the date from \"DD.MM.YYYY\" to \"MM.DD\" and passes\n * all the necessary fields (html, subject, from, date) to the next step.\n */\n\n// Use .map() to transform each incoming item.\nconst results = items.map(item => {\n  // Extract the required fields from the incoming JSON.\n  const { html, subject, from, date: originalDate } = item.json;\n\n  // Check for required fields.\n  if (!html || !originalDate) {\n    // If there is no data, return null to filter this item later.\n    return null;\n  }\n\n  // 1. Split the date string into components (day, month, year).\n  const [day, month] = originalDate.split('.').slice(0, 2);\n\n  // 2. Form a new string in the \"MM.DD\" format.\n  const newDate = `${month}.${day}`;\n\n  // 3. Return a new object in the structure expected by\n  // the next node (LLM).\n  return {\n    json: {\n      html,\n      subject,\n      from,\n      date: newDate\n    }\n  };\n});\n\n// Filter out empty results and return the array for the next node.\nreturn results.filter(item => item !== null);\n"
      },
      "typeVersion": 2
    },
    {
      "id": "4bd967a6-cd5c-4225-a785-fda4f227979a",
      "name": "Crear plantilla",
      "type": "n8n-nodes-base.code",
      "position": [
        1040,
        -128
      ],
      "parameters": {
        "jsCode": "/**\n * This code is intended for use in the \"Code\" node in n8n.\n * It takes an array of topics and creates a single,\n * well-formatted HTML email for sending.\n *\n * This node replaces the nodes \"Formatting\", \"Split\", and \"Sanitizer\".\n */\n\n// Get the array of topics from the previous node.\nconst topics = $json.topics;\n\n// Check if there are topics to process.\nif (!Array.isArray(topics) || topics.length === 0) {\n  return []; // If there are no topics, stop the workflow.\n}\n\n// --- Create HTML markup for each news item ---\nconst topicsHtml = topics.map((topic, index) => {\n  // Escape basic HTML characters in the data to avoid breaking the markup.\n  const escapeHtml = (unsafe) => {\n    if (!unsafe) return '';\n    return unsafe\n         .replace(/&/g, \"&amp;\")\n         .replace(/</g, \"&lt;\")\n         .replace(/>/g, \"&gt;\")\n         .replace(/\\\"/g, \"&quot;\")\n         .replace(/'/g, \"&#039;\");\n  };\n\n  const title = escapeHtml(topic.title);\n  const descr = escapeHtml(topic.descr).replace(/\\n/g, '<br>'); // Preserve line breaks in the description\n  const subject = escapeHtml(topic.subject);\n  const from = escapeHtml(topic.from);\n  const date = escapeHtml(topic.date);\n\n  // Build a nice HTML block for a single news item.\n  return `\n    <div style=\"margin-bottom: 24px; padding-bottom: 16px; border-bottom: 1px solid #eeeeee;\">\n      <h3 style=\"margin: 0 0 8px 0; font-size: 18px; color: #1a1a1a;\">\n        ${index + 1}. ${title}\n      </h3>\n      <p style=\"margin: 0 0 12px 0; font-size: 16px; color: #333333; line-height: 1.5;\">\n        ${descr}\n      </p>\n      <p style=\"margin: 0; font-size: 14px; color: #777777; font-style: italic;\">\n        ${subject}<br>\n        → ${from} - ${date}\n      </p>\n    </div>\n  `;\n}).join(''); // Join all HTML blocks into a single string.\n\n// --- Wrap everything in a full HTML document with styles ---\nconst finalHtml = `\n  <!DOCTYPE html>\n  <html>\n  <head>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Ваш новостной дайджест</title>\n  </head>\n  <body style=\"margin: 0; padding: 0; background-color: #f7f7f7; font-family: Arial, sans-serif;\">\n    <table width=\"100%\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\">\n      <tr>\n        <td align=\"center\" style=\"padding: 20px;\">\n          <table width=\"600\" border=\"0\" cellpadding=\"20\" cellspacing=\"0\" style=\"background-color: #ffffff; border-radius: 8px;\">\n            <tr>\n              <td>\n                <h1 style=\"text-align: center; color: #1a1a1a;\">Новостной дайджест</h1>\n                ${topicsHtml}\n              </td>\n            </tr>\n          </table>\n        </td>\n      </tr>\n    </table>\n  </body>\n  </html>\n`;\n\n// Return the result. In the \"Send Email\" node use {{ $json.htmlBody }}\nreturn [{ json: { htmlBody: finalHtml } }];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "57cc3b99-7a91-492f-8d5c-cbf0da079d16",
      "name": "Enviar un mensaje",
      "type": "n8n-nodes-base.gmail",
      "position": [
        1264,
        -128
      ],
      "webhookId": "74e87896-9cca-4dc0-98bb-7e8f712c5d01",
      "parameters": {
        "sendTo": "your-email@example.com",
        "message": "={{ $json.htmlBody }}",
        "options": {},
        "subject": "Your-subject"
      },
      "credentials": {
        "gmailOAuth2": {
          "id": "sqe7HFlBnGaSLwH9",
          "name": "Gmail account"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "363983e4-7be4-4319-8fdb-dd8ff39200e5",
      "name": "Activador programado",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        144,
        64
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "triggerAtHour": 16
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "06729a53-d537-4a80-8aed-b1032b858390",
      "name": "Nota adhesiva",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        144,
        -208
      ],
      "parameters": {
        "color": 4,
        "width": 320,
        "height": 240,
        "content": "## Try this out!\nSend a number to your Telegram bot (e.g., 2) and get a neatly formatted digest of all Gmail newsletters received since that date. Each email is summarized by an LLM into concise topics, merged into a single Telegram message, automatically split into chunks to fit Telegram limits, and safely formatted as HTML."
      },
      "typeVersion": 1
    },
    {
      "id": "00d59259-5d92-458d-9b8e-bc7bf0f58979",
      "name": "Nota adhesiva1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        576,
        0
      ],
      "parameters": {
        "color": 7,
        "width": 1152,
        "height": 256,
        "content": "## Iterates over each message"
      },
      "typeVersion": 1
    },
    {
      "id": "351eb40c-ba0a-4ea6-9f14-d7eabbf956e7",
      "name": "Nota adhesiva2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        800,
        -192
      ],
      "parameters": {
        "color": 7,
        "width": 656,
        "height": 192,
        "content": "## Clean up the text and forms the final message"
      },
      "typeVersion": 1
    },
    {
      "id": "bddb5d4d-629a-4bfd-bf26-b60451949144",
      "name": "Enviar a un modelo",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "position": [
        1488,
        144
      ],
      "parameters": {
        "modelId": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4.1-mini",
          "cachedResultName": "GPT-4.1-MINI"
        },
        "options": {},
        "messages": {
          "values": [
            {
              "content": "=You are a specialist in analyzing email newsletters. Create a brief summary of the email in JSON format:\n\n`{ \"topics\": [ { \"title\": ..., \"descr\": ..., \"subject\": ..., \"from\": ..., \"date\": ... } ] }`\n\nFor each news item within a block, create a separate topic with a brief one-sentence description, even if they are listed or under a single headline. Do not combine them into one topic.\n\nHowever, if the email is from ____, combine each block (for example, \"____\") by listing the topics in the description.\n\nIf the email is from ____, ignore the sections \"____\" and \"____\".\n\nAll values in your JSON must be in ____ language, except for the subject. The subject—{{ $json.subject }}—must remain untranslated.\n\nHere is the subject: {{ $json.subject }}\nHere is the from: {{ $json.from }}\nHere is the date: {{ $json.date }}\n\nHere is the email:\n{{ $json.html }}"
            }
          ]
        },
        "jsonOutput": true
      },
      "credentials": {
        "openAiApi": {
          "id": "UZtYaio4OAcJGlV9",
          "name": "OpenAi account"
        }
      },
      "typeVersion": 1.8
    }
  ],
  "active": false,
  "pinData": {},
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "53fdca83-a1b5-4866-bed8-0b3322de6bc5",
  "connections": {
    "df46e906-1a21-47c3-9168-900ee58c3730": {
      "main": [
        [
          {
            "node": "bddb5d4d-629a-4bfd-bf26-b60451949144",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "31e5402b-7146-4955-ae7b-ee4dd3ecc583": {
      "main": [
        [
          {
            "node": "4bd967a6-cd5c-4225-a785-fda4f227979a",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "3f688cd5-ac4b-4965-a9d4-2220cee11440": {
      "main": [
        [
          {
            "node": "104254b9-51ea-4655-9e49-38dd3b200929",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "4bd967a6-cd5c-4225-a785-fda4f227979a": {
      "main": [
        [
          {
            "node": "57cc3b99-7a91-492f-8d5c-cbf0da079d16",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "d77aad78-85fa-4dd1-9227-6636b023dc04": {
      "main": [
        [
          {
            "node": "31e5402b-7146-4955-ae7b-ee4dd3ecc583",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "3f688cd5-ac4b-4965-a9d4-2220cee11440",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "bddb5d4d-629a-4bfd-bf26-b60451949144": {
      "main": [
        [
          {
            "node": "d77aad78-85fa-4dd1-9227-6636b023dc04",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "104254b9-51ea-4655-9e49-38dd3b200929": {
      "main": [
        [
          {
            "node": "df46e906-1a21-47c3-9168-900ee58c3730",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "363983e4-7be4-4319-8fdb-dd8ff39200e5": {
      "main": [
        [
          {
            "node": "8636c298-0e5a-494d-9bd1-beace2be380c",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "8636c298-0e5a-494d-9bd1-beace2be380c": {
      "main": [
        [
          {
            "node": "d77aad78-85fa-4dd1-9227-6636b023dc04",
            "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?

Intermedio - Productividad personal, IA Multimodal

¿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
Intermedio
Número de nodos13
Categoría2
Tipos de nodos6
Descripción de la dificultad

Adecuado para usuarios con experiencia intermedia, flujos de trabajo de complejidad media con 6-15 nodos

Enlaces externos
Ver en n8n.io

Compartir este flujo de trabajo

Categorías

Categorías: 34