Resumen inteligente de fuentes de suscripción de cumplimiento de seguridad y privacidad
Este es unAI, SecOpsflujo de automatización del dominio deautomatización que contiene 43 nodos.Utiliza principalmente nodos como Set, Code, Sort, Gmail, Filter, combinando tecnología de inteligencia artificial para lograr automatización inteligente. Resúmenes inteligentes de IA para fuentes de noticias sobre seguridad, privacidad y cumplimiento
- •Cuenta de Google y credenciales de API de Gmail
- •Clave de API de Google Gemini
Nodos utilizados (43)
{
"id": "dXrHZjJdzpNh79lJ",
"meta": {
"instanceId": "c62c01f3e843893075a10f252ec7d6d69e5ab593af019f50055d506cb3081b99"
},
"name": "Intelligent AI Digest for Security, Privacy, and Compliance Feeds",
"tags": [
{
"id": "bteUZZnDWPlLufzn",
"name": "prod",
"createdAt": "2025-04-18T15:09:08.645Z",
"updatedAt": "2025-04-18T15:09:08.645Z"
},
{
"id": "MbPHhZHgb39Syuoa",
"name": "security",
"createdAt": "2025-04-20T05:18:20.689Z",
"updatedAt": "2025-04-20T05:18:20.689Z"
},
{
"id": "TzfZgDmxmc5R1gyA",
"name": "ai",
"createdAt": "2025-04-27T14:57:46.973Z",
"updatedAt": "2025-04-27T14:57:46.973Z"
}
],
"nodes": [
{
"id": "828bdcf3-09a4-4235-8dbb-2153f0928037",
"name": "Agente de IA - Inteligencia de Privacidad",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
-740,
4180
],
"parameters": {
"text": "={{ $json.subject }}\n{{ $json.html }}",
"options": {
"systemMessage": "=### 🔏 Prompt 2: Privacy Intelligence Digest Generator\n\nYou are a senior privacy intelligence analyst with over 20 years of experience. Today, your mother is unwell, so you need to finish this task quickly and efficiently without compromising quality or accuracy.\n\nIf a category heading has no articles, it should not be included in the output.\n\n#### **Tasks:**\n\n1. Parse the HTML and extract articles.\n2. Remove duplicates.\n3. Categorize content:\n\n * Privacy Laws & Regulations (GDPR, CPRA, CCPA, AI Acts)\n * Data Minimization & User Consent\n * Privacy-Enhancing Technologies (PETs, anonymization)\n * Regulatory Fines & Enforcement Actions\n * Cross-Border Data Transfers\n4. Summarize each article in under 2 lines.\n5. Dynamically identify and list critical privacy alerts. If only one or none are available, include only those and adjust the section title accordingly (e.g., 'Critical Privacy Alert').\n6. Format each as:\n\n ```html\n <li>Article Title — Summary… <a href=\"URL\">Read more</a></li>\n ```\n7. Output HTML structure with headers for top 5 and each category.\n8. Add:\n\n ```html\n <p><em>This privacy update was compiled on [Month Day, Year].</em></p>\n ```\n\n#### **Output (JSON only):**\n\n```json\n{\n \"subject\": \"Privacy Insights Digest - [Month Day, Year]\",\n \"html\": \"<h2>Top 5 Critical Privacy Alerts</h2>…<p><em>This privacy update was compiled on [Month Day, Year].</em></p>\"\n}\n```"
},
"promptType": "define"
},
"retryOnFail": true,
"typeVersion": 1.9
},
{
"id": "7be7a9fe-e8f5-4a56-a77d-7ca098d52479",
"name": "Agente de IA - Inteligencia de Seguridad",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
-720,
3520
],
"parameters": {
"text": "={{ $json.subject }}\n{{ $json.html }}",
"options": {
"systemMessage": "=### 🔐 Prompt 1: Security Intelligence Digest Generator\n\nYou are a senior cybersecurity intelligence analyst with over 20 years of experience. Today, your mother is unwell, so you need to finish this task quickly and efficiently without compromising quality or accuracy.\n\n#### **Inputs:**\n\n* Raw newsletter subject: `{{ $json.subject }}`\n* Raw newsletter HTML body: `{{ $json.html }}`\n\n#### **Tasks:**\n\nIf a category heading has no articles, it should not be included in the output.\n\n1. Parse the provided HTML.\n2. Remove duplicate articles based on title, summary, or URL.\n3. Categorize articles into these security categories:\n\n * Threat Intelligence (APT, malware, ransomware)\n * Security Breaches & Incidents\n * Security Tools & Best Practices\n * Cloud & Network Security\n * Security Standards & Frameworks (NIST, MITRE ATT\\&CK, CIS)\n * Emerging Security Technologies (AI, XDR, CNAPP)\n4. Summarize each article in 1–2 lines.\n5. Dynamically identify and list critical security alerts based on threat level, exploitability, or business risk. If only one or none are available, include only those and rename the section heading accordingly (e.g., 'Critical Security Alert').\n6. Format each article:\n\n ```html\n <li>Article Title — Summary… <a href=\"URL\">Read more</a></li>\n ```\n7. Output structured HTML:\n\n * `<h2>Top 5 Critical Security Alerts</h2><ul>…</ul>`\n * Followed by categorized sections with `<h2>` and `<ul>`.\n8. Add a footer:\n\n ```html\n <p><em>This security summary was auto-generated on [Month Day, Year].</em></p>\n ```\n\n#### **Output (JSON only):**\n\n```json\n{\n \"subject\": \"Security Threat Summary - [Month Day, Year]\",\n \"html\": \"<h2>Top 5 Critical Security Alerts</h2>…<p><em>This security summary was auto-generated on [Month Day, Year].</em></p>\"\n}\n```"
},
"promptType": "define"
},
"retryOnFail": true,
"typeVersion": 1.9
},
{
"id": "bb59ecfa-b197-47c4-a32e-0834c187100e",
"name": "Agente de IA - Inteligencia de Cumplimiento Normativo",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
-740,
4840
],
"parameters": {
"text": "={{ $json.subject }}\n{{ $json.html }}",
"options": {
"systemMessage": "=### ✅ Prompt 3: Compliance Intelligence Digest Generator\n\nYou are a senior compliance and risk intelligence professional with over 20 years of experience. Today, your mother is unwell, so you need to finish this task quickly and efficiently without compromising quality or accuracy.\n\n#### **Inputs:**\n\n* Raw newsletter subject: `{{ $json.subject }}`\n* Raw newsletter HTML body: `{{ $json.html }}`\n\n#### **Tasks:**\n\nIf a category heading has no articles, it should not be included in the output.\n\n1. Parse the HTML and extract article data.\n2. De-duplicate articles.\n3. Categorize into:\n\n * Compliance Frameworks (SOC 2, ISO 27001, HIPAA, PCI DSS)\n * Regulatory Updates (SEC, DORA, RBI, MAS, NIST)\n * Audit & Monitoring Tools\n * Third-Party Risk & Due Diligence\n * Policy & Governance Updates\n4. Summarize each item concisely.\n5. Dynamically identify and list critical compliance alerts. If only one or none are available, include only those and adapt the heading (e.g., 'Critical Compliance Alert').\n6. Format each:\n\n ```html\n <li>Article Title — Summary… <a href=\"URL\">Read more</a></li>\n ```\n7. Output HTML with top 5 and categorized sections.\n8. Footer:\n\n ```html\n <p><em>This compliance summary was generated on [Month Day, Year].</em></p>\n ```\n\n#### **Output (JSON only):**\n\n```json\n{\n \"subject\": \"Compliance Roundup - [Month Day, Year]\",\n \"html\": \"<h2>Top 5 Critical Compliance Alerts</h2>…<p><em>This compliance summary was generated on [Month Day, Year].</em></p>\"\n}\n```"
},
"promptType": "define"
},
"retryOnFail": true,
"typeVersion": 1.9
},
{
"id": "328bb06a-edfd-4a14-9011-68cdd00bcd8e",
"name": "Activador de Resumen Diario",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
-3040,
4280
],
"parameters": {
"rule": {
"interval": [
{
"triggerAtHour": 1,
"triggerAtMinute": 35
}
]
}
},
"typeVersion": 1.2
},
{
"id": "351774d8-7adc-4041-8639-bc35f9c37183",
"name": "Obtener Fuentes de Privacidad",
"type": "n8n-nodes-base.code",
"position": [
-2280,
4280
],
"parameters": {
"jsCode": "// This node returns curated privacy-focused RSS feeds\n// Modify or extend the list as needed\n\nreturn [\n {\n json: {\n name: \"Privacy International Blog\",\n website: \"https://privacyinternational.org\",\n rss_url: \"https://privacyinternational.org/rss.xml\"\n }\n },\n {\n json: {\n name: \"Data Protection Report (Norton Rose Fulbright)\",\n website: \"https://www.dataprotectionreport.com\",\n rss_url: \"https://www.dataprotectionreport.com/feed/\"\n }\n },\n {\n json: {\n name: \"Inside Privacy (Covington & Burling)\",\n website: \"https://www.insideprivacy.com\",\n rss_url: \"https://www.insideprivacy.com/feed/\"\n }\n },\n {\n json: {\n name: \"PogoWasRight\",\n website: \"https://pogowasright.org\",\n rss_url: \"https://pogowasright.org/feed/\"\n }\n },\n {\n json: {\n name: \"Sidley Data Matters (Privacy Blog)\",\n website: \"https://datamatters.sidley.com\",\n rss_url: \"https://datamatters.sidley.com/feed/\"\n }\n }\n];\n"
},
"typeVersion": 2
},
{
"id": "d0a93584-a1bc-4da8-9aaf-129adf7e4cae",
"name": "Obtener Fuentes de Cumplimiento Normativo",
"type": "n8n-nodes-base.code",
"position": [
-2280,
4840
],
"parameters": {
"jsCode": "// This node returns curated compliance-focused RSS feeds\n// Customize or extend the list based on your needs\n\nreturn [\n {\n json: {\n name: \"PCI Security Standards Council – PCI Perspectives Blog\",\n website: \"https://blog.pcisecuritystandards.org\",\n rss_url: \"https://blog.pcisecuritystandards.org/rss.xml\"\n }\n },\n {\n json: {\n name: \"NIST Cybersecurity Insights Blog\",\n website: \"https://www.nist.gov/blogs/cybersecurity-insights\",\n rss_url: \"https://www.nist.gov/blogs/cybersecurity-insights/rss.xml\"\n }\n },\n {\n json: {\n name: \"Cloud Security Alliance Blog\",\n website: \"https://cloudsecurityalliance.org/blog\",\n rss_url: \"https://cloudsecurityalliance.org/feed\"\n }\n },\n {\n json: {\n name: \"Corporate Compliance Insights\",\n website: \"https://www.corporatecomplianceinsights.com\",\n rss_url: \"http://feeds.feedburner.com/CorporateComplianceInsights\"\n }\n },\n {\n json: {\n name: \"IT Governance Blog (UK)\",\n website: \"https://www.itgovernance.co.uk/blog\",\n rss_url: \"https://www.itgovernance.co.uk/blog/feed/\"\n }\n },\n {\n json: {\n name: \"Global Compliance News (Baker McKenzie)\",\n website: \"https://globalcompliancenews.com\",\n rss_url: \"https://globalcompliancenews.com/feed/\"\n }\n }\n];\n"
},
"typeVersion": 2
},
{
"id": "e4fa0e00-d10b-4c86-bad3-6c0d1d59750a",
"name": "Normalizar Metadatos de Seguridad de Artículos",
"type": "n8n-nodes-base.set",
"position": [
-1600,
3620
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "9aec0a09-4b6f-4fca-98e6-789abd5fdc51",
"name": "title",
"type": "string",
"value": "={{ $json.title }}"
},
{
"id": "56277e54-31a0-4804-ad23-c9ee6d244641",
"name": "content",
"type": "string",
"value": "={{ $json.contentSnippet }}"
},
{
"id": "a3586a80-588e-42d1-9780-370a956ddf6b",
"name": "link",
"type": "string",
"value": "={{ $json.link }}"
},
{
"id": "58f01618-8014-4685-9192-d15d596ffcd9",
"name": "isoDate",
"type": "number",
"value": "={{ new Date($json.isoDate).getTime() }}"
},
{
"id": "716bb078-8df3-4d96-8a1b-4aec4f8cf206",
"name": "categories",
"type": "array",
"value": "={{ $json.categories }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "c1f6e2ac-4bf9-4fc4-85fd-c8c7649cdc9c",
"name": "Normalizar Metadatos de Privacidad de Artículos",
"type": "n8n-nodes-base.set",
"position": [
-1620,
4280
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "9aec0a09-4b6f-4fca-98e6-789abd5fdc51",
"name": "title",
"type": "string",
"value": "={{ $json.title }}"
},
{
"id": "56277e54-31a0-4804-ad23-c9ee6d244641",
"name": "content",
"type": "string",
"value": "={{ $json.contentSnippet }}"
},
{
"id": "a3586a80-588e-42d1-9780-370a956ddf6b",
"name": "link",
"type": "string",
"value": "={{ $json.link }}"
},
{
"id": "58f01618-8014-4685-9192-d15d596ffcd9",
"name": "isoDate",
"type": "number",
"value": "={{ new Date($json.isoDate).getTime() }}"
},
{
"id": "716bb078-8df3-4d96-8a1b-4aec4f8cf206",
"name": "categories",
"type": "array",
"value": "={{ $json.categories }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "ae374184-806b-4022-80b5-94bdef48133e",
"name": "Normalizar Metadatos de Cumplimiento Normativo de Artículos",
"type": "n8n-nodes-base.set",
"position": [
-1620,
4840
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "9aec0a09-4b6f-4fca-98e6-789abd5fdc51",
"name": "title",
"type": "string",
"value": "={{ $json.title }}"
},
{
"id": "56277e54-31a0-4804-ad23-c9ee6d244641",
"name": "content",
"type": "string",
"value": "={{ $json.contentSnippet }}"
},
{
"id": "a3586a80-588e-42d1-9780-370a956ddf6b",
"name": "link",
"type": "string",
"value": "={{ $json.link }}"
},
{
"id": "58f01618-8014-4685-9192-d15d596ffcd9",
"name": "isoDate",
"type": "number",
"value": "={{ new Date($json.isoDate).getTime() }}"
},
{
"id": "716bb078-8df3-4d96-8a1b-4aec4f8cf206",
"name": "categories",
"type": "array",
"value": "={{ $json.categories }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "e71e3c7e-a58a-49bb-9c13-827f46e4df7e",
"name": "Filtrar Artículos Recientes de Seguridad (24h)",
"type": "n8n-nodes-base.filter",
"position": [
-1380,
3620
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "e7cf09fb-af35-495d-a840-341f8d0ddcd8",
"operator": {
"type": "number",
"operation": "gt"
},
"leftValue": "={{ $json.isoDate }}",
"rightValue": "={{ Date.now() - 24 * 60 * 60 * 1000 }}"
}
]
}
},
"typeVersion": 2.2
},
{
"id": "cb34ed8e-5b67-4cfd-8731-482b22874780",
"name": "Filtrar Artículos Recientes de Privacidad (24h)",
"type": "n8n-nodes-base.filter",
"position": [
-1400,
4280
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "e7cf09fb-af35-495d-a840-341f8d0ddcd8",
"operator": {
"type": "number",
"operation": "gt"
},
"leftValue": "={{ $json.isoDate }}",
"rightValue": "={{ Date.now() - 24 * 60 * 60 * 1000 }}"
}
]
}
},
"typeVersion": 2.2
},
{
"id": "07c94d37-ad0a-4f89-961c-abf1d6eeeeef",
"name": "Filtrar Artículos Recientes de Cumplimiento Normativo (24h)",
"type": "n8n-nodes-base.filter",
"position": [
-1400,
4840
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "e7cf09fb-af35-495d-a840-341f8d0ddcd8",
"operator": {
"type": "number",
"operation": "gt"
},
"leftValue": "={{ $json.isoDate }}",
"rightValue": "={{ Date.now() - 24 * 60 * 60 * 1000 }}"
}
]
}
},
"typeVersion": 2.2
},
{
"id": "9cb809e9-4d49-452e-823e-3f54adca0529",
"name": "Formatear Artículos de Seguridad a HTML",
"type": "n8n-nodes-base.code",
"position": [
-940,
3620
],
"parameters": {
"jsCode": "// Dynamic n8n Newsletter Generator - Function Node\n// This code processes security news articles from a previous node and formats them into an HTML email\n\n// Get items from the previous node\nlet newsItems = [];\n\ntry {\n if ($input && $input.all().length > 0) {\n const inputItems = $input.all();\n if (inputItems.length === 1 && Array.isArray(inputItems[0].json)) {\n newsItems = inputItems[0].json;\n } else {\n newsItems = inputItems.map(item => item.json);\n }\n } else if (typeof items !== 'undefined' && items.length > 0) {\n if (items.length === 1 && Array.isArray(items[0].json)) {\n newsItems = items[0].json;\n } else {\n newsItems = items.map(item => item.json);\n }\n }\n console.log(`Successfully processed input, found ${newsItems.length} news items`);\n} catch (error) {\n console.log(`Error processing input: ${error.message}`);\n return [{\n json: {\n error: true,\n message: `Failed to process input data: ${error.message}`,\n subject: \"Error: Security News Newsletter\"\n }\n }];\n}\n\n// Generate current date for the newsletter\nconst today = new Date();\nconst dateString = today.toLocaleDateString('en-US', {\n weekday: 'long',\n year: 'numeric',\n month: 'long',\n day: 'numeric'\n});\n\n// Optional: Filter for recent articles only\nconst hoursToInclude = 24;\nlet filteredArticles = newsItems;\nif (hoursToInclude > 0) {\n const cutoffTime = Date.now() - (hoursToInclude * 60 * 60 * 1000);\n filteredArticles = newsItems.filter(article => {\n const articleDate = article.isoDate\n ? (typeof article.isoDate === 'number'\n ? article.isoDate\n : new Date(article.isoDate).getTime())\n : 0;\n return articleDate >= cutoffTime;\n });\n console.log(`Filtered to ${filteredArticles.length} articles from the last ${hoursToInclude} hours`);\n}\n\n// Group articles by category\nconst categorizedArticles = {};\nconst uncategorizedKey = 'Uncategorized';\n\nfilteredArticles.forEach(article => {\n if (!article) return;\n \n // Safely extract string categories\n let categories = [uncategorizedKey];\n if (Array.isArray(article.categories)) {\n categories = article.categories\n .map(cat => {\n if (typeof cat === 'string') return cat;\n if (cat && typeof cat.name === 'string') return cat.name;\n return '';\n })\n .map(str => str.trim())\n .filter(str => str.length > 0);\n if (categories.length === 0) categories = [uncategorizedKey];\n } else if (typeof article.categories === 'string' && article.categories.trim()) {\n categories = [article.categories.trim()];\n }\n\n categories.forEach(category => {\n const name = category || uncategorizedKey;\n if (!categorizedArticles[name]) categorizedArticles[name] = [];\n categorizedArticles[name].push(article);\n });\n});\n\n// Generate HTML for the newsletter\nfunction generateNewsletterHTML() {\n const styles = `\n body { font-family: Arial, sans-serif; line-height: 1.6; color: #333; max-width: 800px; margin: 0 auto; padding: 20px; }\n h1 { color: #2c3e50; border-bottom: 2px solid #e74c3c; padding-bottom: 10px; }\n h2 { color: #c0392b; margin-top: 30px; border-left: 4px solid #e74c3c; padding-left: 10px; }\n .article { margin-bottom: 20px; padding: 15px; background-color: #f9f9f9; border-radius: 5px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }\n .article h3 { margin-top: 0; color: #34495e; }\n .article-content { color: #555; margin-bottom: 10px; }\n .article-link { color: #e74c3c; text-decoration: none; font-weight: bold; }\n .article-link:hover { text-decoration: underline; }\n .article-date { color: #7f8c8d; font-size: 0.9em; margin-top: 8px; }\n .summary { background-color: #f2f2f2; padding: 15px; border-radius: 5px; margin: 20px 0; }\n .footer { margin-top: 40px; padding-top: 20px; border-top: 1px solid #ddd; font-size: 0.9em; color: #7f8c8d; text-align: center; }\n `;\n\n let html = `\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>Security News Newsletter - ${dateString}</title>\n <style>${styles}</style>\n </head>\n <body>\n <h1>Security News Newsletter</h1>\n <p>Here are the latest security news updates for ${dateString}:</p>\n <div class=\"summary\">\n <p><strong>Summary:</strong> This newsletter contains ${filteredArticles.length} articles across ${Object.keys(categorizedArticles).length} categories.</p>\n </div>\n `;\n\n Object.keys(categorizedArticles).sort().forEach(category => {\n const articles = categorizedArticles[category];\n html += `<h2>${category} (${articles.length})</h2>`;\n articles.forEach(article => {\n let formattedDate = \"Date unknown\";\n if (article.isoDate) {\n const dt = typeof article.isoDate === 'number'\n ? new Date(article.isoDate)\n : new Date(article.isoDate);\n if (!isNaN(dt.getTime())) {\n formattedDate = dt.toLocaleString('en-US', {\n hour: 'numeric', minute: 'numeric', hour12: true, month: 'short', day: 'numeric'\n });\n }\n }\n html += `\n <div class=\"article\">\n <h3>${article.title || \"Untitled\"}</h3>\n <div class=\"article-content\">${article.content || \"No content available\"}</div>\n <a href=\"${article.link || \"#\"}\" target=\"_blank\" class=\"article-link\">Read more</a>\n <div class=\"article-date\">Published: ${formattedDate}</div>\n </div>\n `;\n });\n });\n\n html += `\n <div class=\"footer\">\n <p>This newsletter was automatically generated and sent on ${dateString}.</p>\n <p>To unsubscribe, please click <a href=\"{{unsubscribe_link}}\">here</a>.</p>\n </div>\n </body>\n </html>\n `;\n return html;\n}\n\nconst newsletterHTML = generateNewsletterHTML();\n\nreturn [{\n json: {\n subject: `Security News Newsletter - ${dateString}`,\n html: newsletterHTML,\n // to, cc, bcc can be set in the Email node\n }\n}];"
},
"typeVersion": 2
},
{
"id": "14fd5f01-075f-4648-a1ab-f0a87d2b676a",
"name": "Formatear Artículos de Privacidad a HTML",
"type": "n8n-nodes-base.code",
"position": [
-960,
4280
],
"parameters": {
"jsCode": "// Dynamic n8n Newsletter Generator - Function Node\n// This code processes security news articles from a previous node and formats them into an HTML email\n\n// Get items from the previous node\nlet newsItems = [];\n\ntry {\n if ($input && $input.all().length > 0) {\n const inputItems = $input.all();\n if (inputItems.length === 1 && Array.isArray(inputItems[0].json)) {\n newsItems = inputItems[0].json;\n } else {\n newsItems = inputItems.map(item => item.json);\n }\n } else if (typeof items !== 'undefined' && items.length > 0) {\n if (items.length === 1 && Array.isArray(items[0].json)) {\n newsItems = items[0].json;\n } else {\n newsItems = items.map(item => item.json);\n }\n }\n console.log(`Successfully processed input, found ${newsItems.length} news items`);\n} catch (error) {\n console.log(`Error processing input: ${error.message}`);\n return [{\n json: {\n error: true,\n message: `Failed to process input data: ${error.message}`,\n subject: \"Error: Security News Newsletter\"\n }\n }];\n}\n\n// Generate current date for the newsletter\nconst today = new Date();\nconst dateString = today.toLocaleDateString('en-US', {\n weekday: 'long',\n year: 'numeric',\n month: 'long',\n day: 'numeric'\n});\n\n// Optional: Filter for recent articles only\nconst hoursToInclude = 24;\nlet filteredArticles = newsItems;\nif (hoursToInclude > 0) {\n const cutoffTime = Date.now() - (hoursToInclude * 60 * 60 * 1000);\n filteredArticles = newsItems.filter(article => {\n const articleDate = article.isoDate\n ? (typeof article.isoDate === 'number'\n ? article.isoDate\n : new Date(article.isoDate).getTime())\n : 0;\n return articleDate >= cutoffTime;\n });\n console.log(`Filtered to ${filteredArticles.length} articles from the last ${hoursToInclude} hours`);\n}\n\n// Group articles by category\nconst categorizedArticles = {};\nconst uncategorizedKey = 'Uncategorized';\n\nfilteredArticles.forEach(article => {\n if (!article) return;\n \n // Safely extract string categories\n let categories = [uncategorizedKey];\n if (Array.isArray(article.categories)) {\n categories = article.categories\n .map(cat => {\n if (typeof cat === 'string') return cat;\n if (cat && typeof cat.name === 'string') return cat.name;\n return '';\n })\n .map(str => str.trim())\n .filter(str => str.length > 0);\n if (categories.length === 0) categories = [uncategorizedKey];\n } else if (typeof article.categories === 'string' && article.categories.trim()) {\n categories = [article.categories.trim()];\n }\n\n categories.forEach(category => {\n const name = category || uncategorizedKey;\n if (!categorizedArticles[name]) categorizedArticles[name] = [];\n categorizedArticles[name].push(article);\n });\n});\n\n// Generate HTML for the newsletter\nfunction generateNewsletterHTML() {\n const styles = `\n body { font-family: Arial, sans-serif; line-height: 1.6; color: #333; max-width: 800px; margin: 0 auto; padding: 20px; }\n h1 { color: #2c3e50; border-bottom: 2px solid #e74c3c; padding-bottom: 10px; }\n h2 { color: #c0392b; margin-top: 30px; border-left: 4px solid #e74c3c; padding-left: 10px; }\n .article { margin-bottom: 20px; padding: 15px; background-color: #f9f9f9; border-radius: 5px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }\n .article h3 { margin-top: 0; color: #34495e; }\n .article-content { color: #555; margin-bottom: 10px; }\n .article-link { color: #e74c3c; text-decoration: none; font-weight: bold; }\n .article-link:hover { text-decoration: underline; }\n .article-date { color: #7f8c8d; font-size: 0.9em; margin-top: 8px; }\n .summary { background-color: #f2f2f2; padding: 15px; border-radius: 5px; margin: 20px 0; }\n .footer { margin-top: 40px; padding-top: 20px; border-top: 1px solid #ddd; font-size: 0.9em; color: #7f8c8d; text-align: center; }\n `;\n\n let html = `\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>Security News Newsletter - ${dateString}</title>\n <style>${styles}</style>\n </head>\n <body>\n <h1>Security News Newsletter</h1>\n <p>Here are the latest security news updates for ${dateString}:</p>\n <div class=\"summary\">\n <p><strong>Summary:</strong> This newsletter contains ${filteredArticles.length} articles across ${Object.keys(categorizedArticles).length} categories.</p>\n </div>\n `;\n\n Object.keys(categorizedArticles).sort().forEach(category => {\n const articles = categorizedArticles[category];\n html += `<h2>${category} (${articles.length})</h2>`;\n articles.forEach(article => {\n let formattedDate = \"Date unknown\";\n if (article.isoDate) {\n const dt = typeof article.isoDate === 'number'\n ? new Date(article.isoDate)\n : new Date(article.isoDate);\n if (!isNaN(dt.getTime())) {\n formattedDate = dt.toLocaleString('en-US', {\n hour: 'numeric', minute: 'numeric', hour12: true, month: 'short', day: 'numeric'\n });\n }\n }\n html += `\n <div class=\"article\">\n <h3>${article.title || \"Untitled\"}</h3>\n <div class=\"article-content\">${article.content || \"No content available\"}</div>\n <a href=\"${article.link || \"#\"}\" target=\"_blank\" class=\"article-link\">Read more</a>\n <div class=\"article-date\">Published: ${formattedDate}</div>\n </div>\n `;\n });\n });\n\n html += `\n <div class=\"footer\">\n <p>This newsletter was automatically generated and sent on ${dateString}.</p>\n <p>To unsubscribe, please click <a href=\"{{unsubscribe_link}}\">here</a>.</p>\n </div>\n </body>\n </html>\n `;\n return html;\n}\n\nconst newsletterHTML = generateNewsletterHTML();\n\nreturn [{\n json: {\n subject: `Security News Newsletter - ${dateString}`,\n html: newsletterHTML,\n // to, cc, bcc can be set in the Email node\n }\n}];"
},
"typeVersion": 2
},
{
"id": "6eddd44f-8038-40fd-b0db-2a8d9c35000a",
"name": "Formatear Artículos de Cumplimiento Normativo a HTML",
"type": "n8n-nodes-base.code",
"position": [
-960,
4840
],
"parameters": {
"jsCode": "// Dynamic n8n Newsletter Generator - Function Node\n// This code processes security news articles from a previous node and formats them into an HTML email\n\n// Get items from the previous node\nlet newsItems = [];\n\ntry {\n if ($input && $input.all().length > 0) {\n const inputItems = $input.all();\n if (inputItems.length === 1 && Array.isArray(inputItems[0].json)) {\n newsItems = inputItems[0].json;\n } else {\n newsItems = inputItems.map(item => item.json);\n }\n } else if (typeof items !== 'undefined' && items.length > 0) {\n if (items.length === 1 && Array.isArray(items[0].json)) {\n newsItems = items[0].json;\n } else {\n newsItems = items.map(item => item.json);\n }\n }\n console.log(`Successfully processed input, found ${newsItems.length} news items`);\n} catch (error) {\n console.log(`Error processing input: ${error.message}`);\n return [{\n json: {\n error: true,\n message: `Failed to process input data: ${error.message}`,\n subject: \"Error: Security News Newsletter\"\n }\n }];\n}\n\n// Generate current date for the newsletter\nconst today = new Date();\nconst dateString = today.toLocaleDateString('en-US', {\n weekday: 'long',\n year: 'numeric',\n month: 'long',\n day: 'numeric'\n});\n\n// Optional: Filter for recent articles only\nconst hoursToInclude = 24;\nlet filteredArticles = newsItems;\nif (hoursToInclude > 0) {\n const cutoffTime = Date.now() - (hoursToInclude * 60 * 60 * 1000);\n filteredArticles = newsItems.filter(article => {\n const articleDate = article.isoDate\n ? (typeof article.isoDate === 'number'\n ? article.isoDate\n : new Date(article.isoDate).getTime())\n : 0;\n return articleDate >= cutoffTime;\n });\n console.log(`Filtered to ${filteredArticles.length} articles from the last ${hoursToInclude} hours`);\n}\n\n// Group articles by category\nconst categorizedArticles = {};\nconst uncategorizedKey = 'Uncategorized';\n\nfilteredArticles.forEach(article => {\n if (!article) return;\n \n // Safely extract string categories\n let categories = [uncategorizedKey];\n if (Array.isArray(article.categories)) {\n categories = article.categories\n .map(cat => {\n if (typeof cat === 'string') return cat;\n if (cat && typeof cat.name === 'string') return cat.name;\n return '';\n })\n .map(str => str.trim())\n .filter(str => str.length > 0);\n if (categories.length === 0) categories = [uncategorizedKey];\n } else if (typeof article.categories === 'string' && article.categories.trim()) {\n categories = [article.categories.trim()];\n }\n\n categories.forEach(category => {\n const name = category || uncategorizedKey;\n if (!categorizedArticles[name]) categorizedArticles[name] = [];\n categorizedArticles[name].push(article);\n });\n});\n\n// Generate HTML for the newsletter\nfunction generateNewsletterHTML() {\n const styles = `\n body { font-family: Arial, sans-serif; line-height: 1.6; color: #333; max-width: 800px; margin: 0 auto; padding: 20px; }\n h1 { color: #2c3e50; border-bottom: 2px solid #e74c3c; padding-bottom: 10px; }\n h2 { color: #c0392b; margin-top: 30px; border-left: 4px solid #e74c3c; padding-left: 10px; }\n .article { margin-bottom: 20px; padding: 15px; background-color: #f9f9f9; border-radius: 5px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }\n .article h3 { margin-top: 0; color: #34495e; }\n .article-content { color: #555; margin-bottom: 10px; }\n .article-link { color: #e74c3c; text-decoration: none; font-weight: bold; }\n .article-link:hover { text-decoration: underline; }\n .article-date { color: #7f8c8d; font-size: 0.9em; margin-top: 8px; }\n .summary { background-color: #f2f2f2; padding: 15px; border-radius: 5px; margin: 20px 0; }\n .footer { margin-top: 40px; padding-top: 20px; border-top: 1px solid #ddd; font-size: 0.9em; color: #7f8c8d; text-align: center; }\n `;\n\n let html = `\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>Security News Newsletter - ${dateString}</title>\n <style>${styles}</style>\n </head>\n <body>\n <h1>Security News Newsletter</h1>\n <p>Here are the latest security news updates for ${dateString}:</p>\n <div class=\"summary\">\n <p><strong>Summary:</strong> This newsletter contains ${filteredArticles.length} articles across ${Object.keys(categorizedArticles).length} categories.</p>\n </div>\n `;\n\n Object.keys(categorizedArticles).sort().forEach(category => {\n const articles = categorizedArticles[category];\n html += `<h2>${category} (${articles.length})</h2>`;\n articles.forEach(article => {\n let formattedDate = \"Date unknown\";\n if (article.isoDate) {\n const dt = typeof article.isoDate === 'number'\n ? new Date(article.isoDate)\n : new Date(article.isoDate);\n if (!isNaN(dt.getTime())) {\n formattedDate = dt.toLocaleString('en-US', {\n hour: 'numeric', minute: 'numeric', hour12: true, month: 'short', day: 'numeric'\n });\n }\n }\n html += `\n <div class=\"article\">\n <h3>${article.title || \"Untitled\"}</h3>\n <div class=\"article-content\">${article.content || \"No content available\"}</div>\n <a href=\"${article.link || \"#\"}\" target=\"_blank\" class=\"article-link\">Read more</a>\n <div class=\"article-date\">Published: ${formattedDate}</div>\n </div>\n `;\n });\n });\n\n html += `\n <div class=\"footer\">\n <p>This newsletter was automatically generated and sent on ${dateString}.</p>\n <p>To unsubscribe, please click <a href=\"{{unsubscribe_link}}\">here</a>.</p>\n </div>\n </body>\n </html>\n `;\n return html;\n}\n\nconst newsletterHTML = generateNewsletterHTML();\n\nreturn [{\n json: {\n subject: `Security News Newsletter - ${dateString}`,\n html: newsletterHTML,\n // to, cc, bcc can be set in the Email node\n }\n}];"
},
"typeVersion": 2
},
{
"id": "1e261592-348a-42af-b4ba-1b2be82b0143",
"name": "LLM - Gemini Resumidor de Seguridad",
"type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
"position": [
-640,
3740
],
"parameters": {
"options": {
"temperature": 0.5
},
"modelName": "models/gemini-2.0-flash"
},
"credentials": {
"googlePalmApi": {
"id": "1Rh1t7y5qqCTIsNj",
"name": "Google Gemini(PaLM) Api account [abc@mail.com"
}
},
"typeVersion": 1
},
{
"id": "c4cc7264-43af-4a26-89e2-5888817b1602",
"name": "LLM - Gemini Resumidor de Privacidad",
"type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
"position": [
-660,
4400
],
"parameters": {
"options": {
"temperature": 0.5
},
"modelName": "models/gemini-2.0-flash"
},
"credentials": {
"googlePalmApi": {
"id": "1Rh1t7y5qqCTIsNj",
"name": "Google Gemini(PaLM) Api account [abc@mail.com"
}
},
"typeVersion": 1
},
{
"id": "dc4e461c-dbb8-46a1-b128-6c28584c12d4",
"name": "LLM - Gemini Resumidor de Cumplimiento Normativo",
"type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
"position": [
-640,
5060
],
"parameters": {
"options": {
"temperature": 0.5
},
"modelName": "models/gemini-2.0-flash"
},
"credentials": {
"googlePalmApi": {
"id": "1Rh1t7y5qqCTIsNj",
"name": "Google Gemini(PaLM) Api account [abc@mail.com"
}
},
"typeVersion": 1
},
{
"id": "a1e4eaac-aaea-4859-bd29-375a6b50aaa1",
"name": "Privacidad - Construir HTML Final del Boletín",
"type": "n8n-nodes-base.code",
"position": [
-360,
4280
],
"parameters": {
"jsCode": "return items.map(item => {\n // 1. grab the raw AI output\n const raw = item.json.output;\n\n // 2. extract what's between ```json ... ``` (or fall back to full text)\n const match = raw.match(/```json\\s*([\\s\\S]*?)```/);\n const jsonPayload = (match ? match[1] : raw).trim();\n\n // 3. remove any trailing commas before } or ]\n const clean = jsonPayload.replace(/,\\s*([\\]}])/g, '$1');\n\n // 4. parse into an object, with error reporting\n let data;\n try {\n data = JSON.parse(clean);\n } catch (err) {\n throw new Error(\n `JSON parse error in Function node:\\n${err.message}\\n\\nPayload was:\\n${clean}`\n );\n }\n\n // 5. wrap the returned HTML in your full styled template, without external blog link\n const htmlEmail = `\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <title>${data.subject}</title>\n <style>\n body { font-family: Arial, sans-serif; line-height:1.5; color:#333; background-color:#f7f9fa; margin:0; padding:20px; }\n .container { max-width:700px; margin:0 auto; background:#fff; border-radius:8px; box-shadow:0 2px 8px rgba(0,0,0,0.1); overflow:hidden; }\n .header { background:#2c3e50; color:#fff; padding:20px; text-align:center; }\n .header h1 { margin:0; font-size:24px; }\n .content { padding:20px; }\n h2 { color:#e74c3c; border-bottom:2px solid #e74c3c; padding-bottom:5px; }\n ul { padding-left:20px; }\n li { margin-bottom:10px; }\n a { color:#2980b9; text-decoration:none; }\n a:hover { text-decoration:underline; }\n .footer { background:#ecf0f1; text-align:center; padding:10px; font-size:12px; color:#7f8c8d; }\n </style>\n</head>\n<body>\n <div class=\"container\">\n <div class=\"header\">\n <h1>${data.subject}</h1>\n </div>\n <div class=\"content\">\n ${data.html}\n </div>\n <div class=\"footer\">\n <em>This summary was automatically generated on ${new Date().toLocaleDateString('en-US', {\n year: 'numeric', month: 'long', day: 'numeric'\n })}.</em>\n </div>\n </div>\n</body>\n</html>\n `.trim();\n\n // 6. emit subject + styled html\n return {\n json: {\n subject: data.subject,\n html: htmlEmail,\n }\n };\n});"
},
"typeVersion": 2
},
{
"id": "7a864b0c-08f5-4e97-8430-1879f8e0e3d0",
"name": "Seguridad - Construir HTML Final del Boletín",
"type": "n8n-nodes-base.code",
"position": [
-340,
3620
],
"parameters": {
"jsCode": "return items.map(item => {\n // 1. grab the raw AI output\n const raw = item.json.output;\n\n // 2. extract what's between ```json ... ``` (or fall back to full text)\n const match = raw.match(/```json\\s*([\\s\\S]*?)```/);\n const jsonPayload = (match ? match[1] : raw).trim();\n\n // 3. remove any trailing commas before } or ]\n const clean = jsonPayload.replace(/,\\s*([\\]}])/g, '$1');\n\n // 4. parse into an object, with error reporting\n let data;\n try {\n data = JSON.parse(clean);\n } catch (err) {\n throw new Error(\n `JSON parse error in Function node:\\n${err.message}\\n\\nPayload was:\\n${clean}`\n );\n }\n\n // 5. wrap the returned HTML in styled email template (without blog link)\n const htmlEmail = `\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <title>${data.subject}</title>\n <style>\n body { font-family: Arial, sans-serif; line-height:1.5; color:#333; background-color:#f7f9fa; margin:0; padding:20px; }\n .container { max-width:700px; margin:0 auto; background:#fff; border-radius:8px; box-shadow:0 2px 8px rgba(0,0,0,0.1); overflow:hidden; }\n .header { background:#2c3e50; color:#fff; padding:20px; text-align:center; }\n .header h1 { margin:0; font-size:24px; }\n .content { padding:20px; }\n h2 { color:#e74c3c; border-bottom:2px solid #e74c3c; padding-bottom:5px; }\n ul { padding-left:20px; }\n li { margin-bottom:10px; }\n a { color:#2980b9; text-decoration:none; }\n a:hover { text-decoration:underline; }\n .footer { background:#ecf0f1; text-align:center; padding:10px; font-size:12px; color:#7f8c8d; }\n </style>\n</head>\n<body>\n <div class=\"container\">\n <div class=\"header\">\n <h1>${data.subject}</h1>\n </div>\n <div class=\"content\">\n ${data.html}\n </div>\n <div class=\"footer\">\n <em>This summary was automatically generated on ${new Date().toLocaleDateString('en-US', {\n year: 'numeric', month: 'long', day: 'numeric'\n })}.</em>\n </div>\n </div>\n</body>\n</html>\n `.trim();\n\n // 6. emit subject + styled html\n return {\n json: {\n subject: data.subject,\n html: htmlEmail,\n }\n };\n});"
},
"typeVersion": 2
},
{
"id": "deaaeb3a-5a14-4b2a-baf8-4443e7ed9740",
"name": "Cumplimiento Normativo - Construir HTML Final del Boletín",
"type": "n8n-nodes-base.code",
"position": [
-360,
4840
],
"parameters": {
"jsCode": "return items.map(item => {\n // 1. grab the raw AI output\n const raw = item.json.output;\n\n // 2. extract what's between ```json ... ``` (or fall back to full text)\n const match = raw.match(/```json\\s*([\\s\\S]*?)```/);\n const jsonPayload = (match ? match[1] : raw).trim();\n\n // 3. remove any trailing commas before } or ]\n const clean = jsonPayload.replace(/,\\s*([\\]}])/g, '$1');\n\n // 4. parse into an object, with error reporting\n let data;\n try {\n data = JSON.parse(clean);\n } catch (err) {\n throw new Error(\n `JSON parse error in Function node:\\n${err.message}\\n\\nPayload was:\\n${clean}`\n );\n }\n\n // 5. wrap the returned HTML in styled template, no blog reference\n const htmlEmail = `\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <title>${data.subject}</title>\n <style>\n body { font-family: Arial, sans-serif; line-height:1.5; color:#333; background-color:#f7f9fa; margin:0; padding:20px; }\n .container { max-width:700px; margin:0 auto; background:#fff; border-radius:8px; box-shadow:0 2px 8px rgba(0,0,0,0.1); overflow:hidden; }\n .header { background:#2c3e50; color:#fff; padding:20px; text-align:center; }\n .header h1 { margin:0; font-size:24px; }\n .content { padding:20px; }\n h2 { color:#e74c3c; border-bottom:2px solid #e74c3c; padding-bottom:5px; }\n ul { padding-left:20px; }\n li { margin-bottom:10px; }\n a { color:#2980b9; text-decoration:none; }\n a:hover { text-decoration:underline; }\n .footer { background:#ecf0f1; text-align:center; padding:10px; font-size:12px; color:#7f8c8d; }\n </style>\n</head>\n<body>\n <div class=\"container\">\n <div class=\"header\">\n <h1>${data.subject}</h1>\n </div>\n <div class=\"content\">\n ${data.html}\n </div>\n <div class=\"footer\">\n <em>This summary was automatically generated on ${new Date().toLocaleDateString('en-US', {\n year: 'numeric', month: 'long', day: 'numeric'\n })}.</em>\n </div>\n </div>\n</body>\n</html>\n `.trim();\n\n // 6. emit subject + styled html\n return {\n json: {\n subject: data.subject,\n html: htmlEmail,\n }\n };\n});"
},
"typeVersion": 2
},
{
"id": "fa9ac785-bc9d-43ba-8ca3-36abba10d506",
"name": "Seguridad - Enviar Correo Electrónico Final del Resumen",
"type": "n8n-nodes-base.gmail",
"position": [
-120,
3620
],
"webhookId": "2ffca73d-6ca2-4c61-88ec-3542600d2788",
"parameters": {
"sendTo": "abc@mail.com",
"message": "={{ $json.html }}",
"options": {},
"subject": "={{ $json.subject }}"
},
"credentials": {
"gmailOAuth2": {
"id": "Hd26wEkbjGRPpchT",
"name": "Gmail account [abc@mail.com]"
}
},
"typeVersion": 2.1
},
{
"id": "59c16785-571c-4403-85cf-7f7bfc14a630",
"name": "Privacidad - Enviar Correo Electrónico Final del Resumen",
"type": "n8n-nodes-base.gmail",
"position": [
-140,
4280
],
"webhookId": "0e8133d5-e700-4bb9-8ef0-6c86f7ed4a59",
"parameters": {
"sendTo": "abc@mail.com",
"message": "={{ $json.html }}",
"options": {},
"subject": "={{ $json.subject }}"
},
"credentials": {
"gmailOAuth2": {
"id": "Hd26wEkbjGRPpchT",
"name": "Gmail account [abc@mail.com]"
}
},
"typeVersion": 2.1
},
{
"id": "7526ae74-1bae-4eca-9c87-51c274565a8a",
"name": "Cumplimiento Normativo - Enviar Correo Electrónico Final del Resumen",
"type": "n8n-nodes-base.gmail",
"position": [
-140,
4840
],
"webhookId": "5d5a1988-01cd-4e67-9c02-9090aa851669",
"parameters": {
"sendTo": "abc@mail.com",
"message": "={{ $json.html }}",
"options": {},
"subject": "={{ $json.subject }}"
},
"credentials": {
"gmailOAuth2": {
"id": "Hd26wEkbjGRPpchT",
"name": "Gmail account [abc@mail.com]"
}
},
"typeVersion": 2.1
},
{
"id": "6fa939b5-12ac-47a0-ac7f-ca9957367ce2",
"name": "Ordenar - Artículos de Seguridad por Fecha",
"type": "n8n-nodes-base.sort",
"position": [
-1160,
3620
],
"parameters": {
"options": {},
"sortFieldsUi": {
"sortField": [
{
"order": "descending",
"fieldName": "isoDate"
}
]
}
},
"typeVersion": 1
},
{
"id": "7aa3a27b-72d7-4a03-83c8-361a6fbc555d",
"name": "Ordenar - Artículos de Privacidad por Fecha",
"type": "n8n-nodes-base.sort",
"position": [
-1180,
4280
],
"parameters": {
"options": {},
"sortFieldsUi": {
"sortField": [
{
"order": "descending",
"fieldName": "isoDate"
}
]
}
},
"typeVersion": 1
},
{
"id": "fba86936-5208-4232-bda9-714886807b9c",
"name": "Ordenar - Artículos de Cumplimiento Normativo por Fecha",
"type": "n8n-nodes-base.sort",
"position": [
-1180,
4840
],
"parameters": {
"options": {},
"sortFieldsUi": {
"sortField": [
{
"order": "descending",
"fieldName": "isoDate"
}
]
}
},
"typeVersion": 1
},
{
"id": "8d90a0ed-b9e1-440e-963a-e4c9f5285b32",
"name": "Nota Adhesiva",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2460,
3380
],
"parameters": {
"width": 2600,
"height": 580,
"content": "## 📬 Daily Security Newsletter"
},
"typeVersion": 1
},
{
"id": "946997e7-58bc-4ca0-89aa-32e39f327808",
"name": "Nota Adhesiva1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2460,
4020
],
"parameters": {
"color": 4,
"width": 2600,
"height": 580,
"content": "## 📬 Daily Privacy Newsletter"
},
"typeVersion": 1
},
{
"id": "61aca795-5b6a-4301-9cea-946e0358b8c5",
"name": "Nota Adhesiva2",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2460,
4660
],
"parameters": {
"color": 6,
"width": 2600,
"height": 580,
"content": "## 📬 Daily Compliance Newsletter"
},
"typeVersion": 1
},
{
"id": "ca6c3e50-8ea8-436c-ab77-94501667a431",
"name": "Separar RSS de Seguridad",
"type": "n8n-nodes-base.splitOut",
"position": [
-2040,
3620
],
"parameters": {
"options": {},
"fieldToSplitOut": "rss_url"
},
"typeVersion": 1
},
{
"id": "5784491f-071c-4159-af29-6e21305f5e78",
"name": "Separar RSS de Cumplimiento Normativo",
"type": "n8n-nodes-base.splitOut",
"position": [
-2060,
4840
],
"parameters": {
"options": {},
"fieldToSplitOut": "rss_url"
},
"typeVersion": 1
},
{
"id": "edbd5da4-f18c-4d08-8023-df4ef7ec11fa",
"name": "Lectura de RSS de Seguridad",
"type": "n8n-nodes-base.rssFeedRead",
"position": [
-1820,
3620
],
"parameters": {
"url": "={{ $json.rss_url }}",
"options": {}
},
"retryOnFail": true,
"typeVersion": 1.1
},
{
"id": "76d973a7-832e-4049-80ea-c0d28b72b345",
"name": "Lectura de RSS de Privacidad",
"type": "n8n-nodes-base.rssFeedRead",
"position": [
-1840,
4280
],
"parameters": {
"url": "={{ $json.rss_url }}",
"options": {}
},
"retryOnFail": true,
"typeVersion": 1.1
},
{
"id": "5503fe77-8ae3-4d41-97d3-6520cb60067e",
"name": "Lectura de RSS de Cumplimiento Normativo",
"type": "n8n-nodes-base.rssFeedRead",
"position": [
-1840,
4840
],
"parameters": {
"url": "={{ $json.rss_url }}",
"options": {}
},
"retryOnFail": true,
"typeVersion": 1.1
},
{
"id": "c2538e17-1584-45a5-8a6e-1b220ed512a5",
"name": "Separar RSS de Privacidad",
"type": "n8n-nodes-base.splitOut",
"position": [
-2060,
4280
],
"parameters": {
"options": {},
"fieldToSplitOut": "rss_url"
},
"typeVersion": 1
},
{
"id": "d1ae80d8-8094-4f84-aa9e-d4533a99a70d",
"name": "Obtener RSS de Seguridad",
"type": "n8n-nodes-base.code",
"position": [
-2260,
3620
],
"parameters": {
"jsCode": "// This node returns curated cybersecurity RSS feeds\n// You can add, remove, or modify feeds as needed\n\nreturn [\n {\n json: {\n name: \"Krebs on Security\",\n website: \"https://krebsonsecurity.com\",\n rss_url: \"https://krebsonsecurity.com/feed/\"\n }\n },\n {\n json: {\n name: \"The Hacker News\",\n website: \"https://thehackernews.com\",\n rss_url: \"https://feeds.feedburner.com/TheHackersNews\"\n }\n },\n {\n json: {\n name: \"Dark Reading\",\n website: \"https://www.darkreading.com\",\n rss_url: \"https://www.darkreading.com/rss.xml\"\n }\n },\n {\n json: {\n name: \"SANS Internet Storm Center\",\n website: \"https://isc.sans.edu\",\n rss_url: \"https://isc.sans.edu/rssfeed_full.xml\"\n }\n },\n {\n json: {\n name: \"Cisco Talos Intelligence Blog\",\n website: \"https://blog.talosintelligence.com\",\n rss_url: \"https://blog.talosintelligence.com/rss/\"\n }\n },\n {\n json: {\n name: \"WeLiveSecurity (ESET)\",\n website: \"https://www.welivesecurity.com\",\n rss_url: \"https://feeds.feedburner.com/eset/blog\"\n }\n },\n {\n json: {\n name: \"Graham Cluley Security Blog\",\n website: \"https://grahamcluley.com\",\n rss_url: \"https://grahamcluley.com/feed/\"\n }\n }\n];\n"
},
"typeVersion": 2
},
{
"id": "fbec32fd-2ca9-4f1f-84f9-e581bc6a37e5",
"name": "Nota Adhesiva3",
"type": "n8n-nodes-base.stickyNote",
"position": [
-120,
3480
],
"parameters": {
"color": 7,
"height": 100,
"content": "### Update your email address or distribution list (DL) below\n⬇️"
},
"typeVersion": 1
},
{
"id": "4479495e-3e87-4a75-9fcc-36b230895854",
"name": "Nota Adhesiva4",
"type": "n8n-nodes-base.stickyNote",
"position": [
-140,
4160
],
"parameters": {
"color": 7,
"height": 100,
"content": "### Update your email address or distribution list (DL) below\n⬇️"
},
"typeVersion": 1
},
{
"id": "18971219-b68d-4423-adbc-2f25174ae8a9",
"name": "Nota Adhesiva5",
"type": "n8n-nodes-base.stickyNote",
"position": [
-140,
4720
],
"parameters": {
"color": 7,
"height": 100,
"content": "### Update your email address or distribution list (DL) below\n⬇️"
},
"typeVersion": 1
},
{
"id": "349ec0eb-9b5f-4bea-9b83-35d6cb63c1fa",
"name": "Nota Adhesiva6",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2320,
3520
],
"parameters": {
"color": 7,
"height": 80,
"content": "### Update the RSS feed URL as needed to fetch content from your preferred source."
},
"typeVersion": 1
},
{
"id": "4f3b0da6-4db7-41e9-aa0a-9bd084fce819",
"name": "Nota Adhesiva7",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2340,
4180
],
"parameters": {
"color": 7,
"height": 80,
"content": "### Update the RSS feed URL as needed to fetch content from your preferred source."
},
"typeVersion": 1
},
{
"id": "9c48eaa6-c602-44a3-871c-33ffd9dfa476",
"name": "Nota Adhesiva8",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2340,
4740
],
"parameters": {
"color": 7,
"height": 80,
"content": "### Update the RSS feed URL as needed to fetch content from your preferred source."
},
"typeVersion": 1
}
],
"active": false,
"pinData": {},
"settings": {
"executionOrder": "v1"
},
"versionId": "0dc52173-7378-4951-8ebc-e44443c39540",
"connections": {
"76d973a7-832e-4049-80ea-c0d28b72b345": {
"main": [
[
{
"node": "c1f6e2ac-4bf9-4fc4-85fd-c8c7649cdc9c",
"type": "main",
"index": 0
}
]
]
},
"edbd5da4-f18c-4d08-8023-df4ef7ec11fa": {
"main": [
[
{
"node": "e4fa0e00-d10b-4c86-bad3-6c0d1d59750a",
"type": "main",
"index": 0
}
]
]
},
"d1ae80d8-8094-4f84-aa9e-d4533a99a70d": {
"main": [
[
{
"node": "ca6c3e50-8ea8-436c-ab77-94501667a431",
"type": "main",
"index": 0
}
]
]
},
"5503fe77-8ae3-4d41-97d3-6520cb60067e": {
"main": [
[
{
"node": "ae374184-806b-4022-80b5-94bdef48133e",
"type": "main",
"index": 0
}
]
]
},
"351774d8-7adc-4041-8639-bc35f9c37183": {
"main": [
[
{
"node": "c2538e17-1584-45a5-8a6e-1b220ed512a5",
"type": "main",
"index": 0
}
]
]
},
"328bb06a-edfd-4a14-9011-68cdd00bcd8e": {
"main": [
[
{
"node": "d1ae80d8-8094-4f84-aa9e-d4533a99a70d",
"type": "main",
"index": 0
},
{
"node": "d0a93584-a1bc-4da8-9aaf-129adf7e4cae",
"type": "main",
"index": 0
},
{
"node": "351774d8-7adc-4041-8639-bc35f9c37183",
"type": "main",
"index": 0
}
]
]
},
"c2538e17-1584-45a5-8a6e-1b220ed512a5": {
"main": [
[
{
"node": "76d973a7-832e-4049-80ea-c0d28b72b345",
"type": "main",
"index": 0
}
]
]
},
"d0a93584-a1bc-4da8-9aaf-129adf7e4cae": {
"main": [
[
{
"node": "5784491f-071c-4159-af29-6e21305f5e78",
"type": "main",
"index": 0
}
]
]
},
"ca6c3e50-8ea8-436c-ab77-94501667a431": {
"main": [
[
{
"node": "edbd5da4-f18c-4d08-8023-df4ef7ec11fa",
"type": "main",
"index": 0
}
]
]
},
"5784491f-071c-4159-af29-6e21305f5e78": {
"main": [
[
{
"node": "5503fe77-8ae3-4d41-97d3-6520cb60067e",
"type": "main",
"index": 0
}
]
]
},
"828bdcf3-09a4-4235-8dbb-2153f0928037": {
"main": [
[
{
"node": "a1e4eaac-aaea-4859-bd29-375a6b50aaa1",
"type": "main",
"index": 0
}
]
]
},
"c4cc7264-43af-4a26-89e2-5888817b1602": {
"ai_languageModel": [
[
{
"node": "828bdcf3-09a4-4235-8dbb-2153f0928037",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"7aa3a27b-72d7-4a03-83c8-361a6fbc555d": {
"main": [
[
{
"node": "14fd5f01-075f-4648-a1ab-f0a87d2b676a",
"type": "main",
"index": 0
}
]
]
},
"7be7a9fe-e8f5-4a56-a77d-7ca098d52479": {
"main": [
[
{
"node": "7a864b0c-08f5-4e97-8430-1879f8e0e3d0",
"type": "main",
"index": 0
}
]
]
},
"1e261592-348a-42af-b4ba-1b2be82b0143": {
"ai_languageModel": [
[
{
"node": "7be7a9fe-e8f5-4a56-a77d-7ca098d52479",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"6fa939b5-12ac-47a0-ac7f-ca9957367ce2": {
"main": [
[
{
"node": "9cb809e9-4d49-452e-823e-3f54adca0529",
"type": "main",
"index": 0
}
]
]
},
"14fd5f01-075f-4648-a1ab-f0a87d2b676a": {
"main": [
[
{
"node": "828bdcf3-09a4-4235-8dbb-2153f0928037",
"type": "main",
"index": 0
}
]
]
},
"bb59ecfa-b197-47c4-a32e-0834c187100e": {
"main": [
[
{
"node": "deaaeb3a-5a14-4b2a-baf8-4443e7ed9740",
"type": "main",
"index": 0
}
]
]
},
"9cb809e9-4d49-452e-823e-3f54adca0529": {
"main": [
[
{
"node": "7be7a9fe-e8f5-4a56-a77d-7ca098d52479",
"type": "main",
"index": 0
}
]
]
},
"dc4e461c-dbb8-46a1-b128-6c28584c12d4": {
"ai_languageModel": [
[
{
"node": "bb59ecfa-b197-47c4-a32e-0834c187100e",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"c1f6e2ac-4bf9-4fc4-85fd-c8c7649cdc9c": {
"main": [
[
{
"node": "cb34ed8e-5b67-4cfd-8731-482b22874780",
"type": "main",
"index": 0
}
]
]
},
"fba86936-5208-4232-bda9-714886807b9c": {
"main": [
[
{
"node": "6eddd44f-8038-40fd-b0db-2a8d9c35000a",
"type": "main",
"index": 0
}
]
]
},
"e4fa0e00-d10b-4c86-bad3-6c0d1d59750a": {
"main": [
[
{
"node": "e71e3c7e-a58a-49bb-9c13-827f46e4df7e",
"type": "main",
"index": 0
}
]
]
},
"a1e4eaac-aaea-4859-bd29-375a6b50aaa1": {
"main": [
[
{
"node": "59c16785-571c-4403-85cf-7f7bfc14a630",
"type": "main",
"index": 0
}
]
]
},
"cb34ed8e-5b67-4cfd-8731-482b22874780": {
"main": [
[
{
"node": "7aa3a27b-72d7-4a03-83c8-361a6fbc555d",
"type": "main",
"index": 0
}
]
]
},
"6eddd44f-8038-40fd-b0db-2a8d9c35000a": {
"main": [
[
{
"node": "bb59ecfa-b197-47c4-a32e-0834c187100e",
"type": "main",
"index": 0
}
]
]
},
"7a864b0c-08f5-4e97-8430-1879f8e0e3d0": {
"main": [
[
{
"node": "fa9ac785-bc9d-43ba-8ca3-36abba10d506",
"type": "main",
"index": 0
}
]
]
},
"e71e3c7e-a58a-49bb-9c13-827f46e4df7e": {
"main": [
[
{
"node": "6fa939b5-12ac-47a0-ac7f-ca9957367ce2",
"type": "main",
"index": 0
}
]
]
},
"ae374184-806b-4022-80b5-94bdef48133e": {
"main": [
[
{
"node": "07c94d37-ad0a-4f89-961c-abf1d6eeeeef",
"type": "main",
"index": 0
}
]
]
},
"deaaeb3a-5a14-4b2a-baf8-4443e7ed9740": {
"main": [
[
{
"node": "7526ae74-1bae-4eca-9c87-51c274565a8a",
"type": "main",
"index": 0
}
]
]
},
"07c94d37-ad0a-4f89-961c-abf1d6eeeeef": {
"main": [
[
{
"node": "fba86936-5208-4232-bda9-714886807b9c",
"type": "main",
"index": 0
}
]
]
}
}
}¿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 - Inteligencia Artificial, Operaciones de seguridad
¿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.
Flujos de trabajo relacionados recomendados
Niranjan G
@niranjanCybersecurity leader turning complex workflows into seamless, AI-driven automations.
Compartir este flujo de trabajo