セキュリティ・プライバシー・コンプライアンスニュースフィードのスマート要約
上級
これはAI, SecOps分野の自動化ワークフローで、43個のノードを含みます。主にSet, Code, Sort, Gmail, Filterなどのノードを使用、AI技術を活用したスマート自動化を実現。 セキュリティ、プライバシー、コンプライアンス情報源向けのスマートAIサマリー
前提条件
- •Googleアカウント + Gmail API認証情報
- •Google Gemini API Key
ワークフロープレビュー
ノード接続関係を可視化、ズームとパンをサポート
ワークフローをエクスポート
以下のJSON設定をn8nにインポートして、このワークフローを使用できます
{
"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": "AI Agent - プライバシーインテリジェンス",
"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": "AI Agent - セキュリティインテリジェンス",
"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": "AI Agent - コンプライアンスインテリジェンス",
"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": "デイリーダイジェストトリガー",
"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": "プライバシーフィード取得",
"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": "コンプライアンスフィード取得",
"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": "セキュリティ記事メタデータ正規化",
"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": "プライバシー記事メタデータ正規化",
"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": "コンプライアンス記事メタデータ正規化",
"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": "最近のセキュリティ記事フィルタ (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": "最近のプライバシー記事フィルタ (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": "最近のコンプライアンス記事フィルタ (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": "セキュリティ記事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": "プライバシー記事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": "コンプライアンス記事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 セキュリティ要約",
"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 プライバシー要約",
"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 コンプライアンス要約",
"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": "プライバシー最終ニュースレターHTML構築",
"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": "セキュリティ最終ニュースレターHTML構築",
"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": "コンプライアンス最終ニュースレターHTML構築",
"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": "セキュリティ最終ダイジェストメール送信",
"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": "プライバシー最終ダイジェストメール送信",
"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": "コンプライアンス最終ダイジェストメール送信",
"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": "セキュリティ記事日付順ソート",
"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": "プライバシー記事日付順ソート",
"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": "コンプライアンス記事日付順ソート",
"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": "付箋",
"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": "付箋1",
"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": "付箋2",
"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": "セキュリティRSS分割",
"type": "n8n-nodes-base.splitOut",
"position": [
-2040,
3620
],
"parameters": {
"options": {},
"fieldToSplitOut": "rss_url"
},
"typeVersion": 1
},
{
"id": "5784491f-071c-4159-af29-6e21305f5e78",
"name": "コンプライアンスRSS分割",
"type": "n8n-nodes-base.splitOut",
"position": [
-2060,
4840
],
"parameters": {
"options": {},
"fieldToSplitOut": "rss_url"
},
"typeVersion": 1
},
{
"id": "edbd5da4-f18c-4d08-8023-df4ef7ec11fa",
"name": "セキュリティRSS読込",
"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": "プライバシーRSS読込",
"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": "コンプライアンスRSS読込",
"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": "プライバシーRSS分割",
"type": "n8n-nodes-base.splitOut",
"position": [
-2060,
4280
],
"parameters": {
"options": {},
"fieldToSplitOut": "rss_url"
},
"typeVersion": 1
},
{
"id": "d1ae80d8-8094-4f84-aa9e-d4533a99a70d",
"name": "セキュリティRSS取得",
"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": "付箋3",
"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": "付箋4",
"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": "付箋5",
"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": "付箋6",
"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": "付箋7",
"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": "付箋8",
"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
}
]
]
}
}
}よくある質問
このワークフローの使い方は?
上記のJSON設定コードをコピーし、n8nインスタンスで新しいワークフローを作成して「JSONからインポート」を選択、設定を貼り付けて認証情報を必要に応じて変更してください。
このワークフローはどんな場面に適していますか?
上級 - 人工知能, セキュリティ運用
有料ですか?
このワークフローは完全無料です。ただし、ワークフローで使用するサードパーティサービス(OpenAI APIなど)は別途料金が発生する場合があります。
関連ワークフロー
AI ベースのサプライヤー政策と RSS フィード分析とリスクスコアリング
リスクスコアを統合したAIベンダー政策およびRSSフィード分析システム
If
Code
Sort
+
If
Code
Sort
29 ノードKamalraj
人工知能
n8nノードの探索(可視化リファレンスライブラリ内)
n8nノードを可視化リファレンスライブラリで探索
If
Ftp
Set
+
If
Ftp
Set
113 ノードI versus AI
その他
AIによるLinkedInのRSS処理
Gemini AIとRSSソースを使ってLinkedInニュース投稿を自動化
If
Set
Code
+
If
Set
Code
43 ノードClub de Inteligencia Artificial Politécnico CIAP
人工知能
スマートGmailメールラベリング
AIコンテンツ分類に基づくスマートGmailメール管理
If
Set
Code
+
If
Set
Code
18 ノードNiranjan G
サポート
Microsoft Teams会議分析をGPT-4.1、Outlook、Mem.aiを使用して自動化
GPT-4.1、Outlook、Mem.aiを使ってMicrosoft Teams会議の分析を自動化する
If
Set
Code
+
If
Set
Code
61 ノードWayne Simpson
人事
アクセルレーション隊スプリント計画の自動化
OpenAI、Googleカレンダー、Gmailを使ってアジャイルチームのスプリント計画を自動化
If
Set
Code
+
If
Set
Code
52 ノードWillemijn
プロダクト
ワークフロー情報
難易度
上級
ノード数43
カテゴリー2
ノードタイプ11
作成者
Niranjan G
@niranjanCybersecurity leader turning complex workflows into seamless, AI-driven automations.
外部リンク
n8n.ioで表示 →
このワークフローを共有