This workflow corresponds to n8n.io template #17340 — we link there as the canonical source.
The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"id": "M8GJ6xm3TJql7Njs",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "Developer Release Digest",
"tags": [],
"nodes": [
{
"id": "28d2fea3-0a95-4f7a-adb3-710f26cbe105",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-608,
192
],
"parameters": {
"width": 480,
"height": 768,
"content": "## Developer Release Digest\n\n### How it works\n\nThis workflow runs on a schedule to collect developer release updates from a configured set of RSS feeds. It filters the feed entries down to recent, relevant release items, removes noisy matches, then normalizes and groups the results into an HTML email digest. If there are releases to report, it sends the digest using Resend.\n\n### Setup steps\n\n- Configure the Schedule Trigger with the desired run frequency.\n- Update the List of RSS Feeds code node with the RSS sources to monitor.\n- Review the filtering code nodes to ensure the recency window, development build criteria, and noise words match your needs.\n- Set up valid Resend credentials and configure the sender, recipient, and subject fields in the email node.\n\n### Customization\n\nAdjust the RSS feed list, release filtering rules, grouping logic, and HTML template to tailor the digest content and formatting."
},
"typeVersion": 1
},
{
"id": "77452676-bb7c-4a2a-a117-2a8e77d49f2b",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-48,
224
],
"parameters": {
"color": 7,
"width": 864,
"height": 304,
"content": "## Schedule and fetch feeds\n\nStarts the workflow on a schedule, builds the configured list of RSS feed sources, fetches their entries, and adds metadata needed for downstream processing."
},
"typeVersion": 1
},
{
"id": "fc353ab8-7af0-4b7c-b843-4bd22d727944",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
848,
192
],
"parameters": {
"color": 7,
"width": 640,
"height": 320,
"content": "## Filter release items\n\nNarrows fetched RSS entries to relevant developer release content by keeping recent items, selecting development build releases, and removing entries that match noise words."
},
"typeVersion": 1
},
{
"id": "89891711-1ab9-4728-9336-4a89033b3ff9",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
1520,
224
],
"parameters": {
"color": 7,
"width": 640,
"height": 304,
"content": "## Prepare email digest\n\nNormalizes release records into a consistent shape, groups them for presentation, and generates the HTML email body for the digest."
},
"typeVersion": 1
},
{
"id": "2b012584-0f38-4219-8f12-6e9571723361",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
2192,
192
],
"parameters": {
"color": 7,
"width": 416,
"height": 320,
"content": "## Check and send\n\nChecks whether the generated digest contains releases and, when it does, sends the email through Resend."
},
"typeVersion": 1
},
{
"id": "d8e133eb-ceda-4d93-b8f1-de7eaf502e62",
"name": "Every Monday at 9am",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
0,
352
],
"parameters": {
"rule": {
"interval": [
{
"field": "weeks",
"triggerAtDay": [
1
],
"triggerAtHour": 9
}
]
}
},
"typeVersion": 1.3
},
{
"id": "de71fb35-7ecc-45f5-b944-0365c5a3fecb",
"name": "Exclude Non-Stable Releases",
"type": "n8n-nodes-base.code",
"position": [
1120,
352
],
"parameters": {
"jsCode": "const ignoredTitlePatterns = [\n /-dev-/i,\n /\\bdev build\\b/i,\n /\\bsnapshot\\b/i\n];\n\nreturn items.filter(item => {\n const title = item.json.title || \"\";\n\n const isIgnored = ignoredTitlePatterns.some(\n pattern => pattern.test(title)\n );\n\n return !isIgnored;\n});"
},
"typeVersion": 2
},
{
"id": "76758fd2-7c04-4db5-ae2f-f9db8ce4fafe",
"name": "Select Recent Releases",
"type": "n8n-nodes-base.code",
"position": [
896,
352
],
"parameters": {
"jsCode": "const now = new Date();\n\n// Keep items from the last 7 days\nconst cutoff = new Date(\n now.getTime() - (7 * 24 * 60 * 60 * 1000)\n);\n\nconst dateValues = [\n \"isoDate\",\n \"pubDate\",\n \"pubdate\",\n \"published\",\n \"updated\",\n \"created\"\n];\n\nreturn items.filter(item => {\n const data = item.json;\n\n const dateField = dateValues.find(\n field => data[field]\n );\n\n if (!dateField) {\n // Keep for now so we can inspect feeds\n return true;\n }\n\n const publishedDate = new Date(data[dateField]);\n\n return publishedDate >= cutoff;\n});"
},
"typeVersion": 2
},
{
"id": "974d7f7c-fca1-4efb-8a06-a0db55c00024",
"name": "Remove Irrelevant Words",
"type": "n8n-nodes-base.code",
"position": [
1344,
352
],
"parameters": {
"jsCode": "const ignoredTitlePatterns = [\n /\\bchore\\b/i,\n /\\btest\\b/i,\n /\\btests\\b/i,\n /\\btesting\\b/i,\n /\\bdocumentation\\b/i,\n /\\bdocs\\b/i,\n /\\btranslation\\b/i,\n /\\btranslations\\b/i,\n /\\btypo\\b/i,\n /\\bmerge\\b/i,\n /\\bmerged\\b/i,\n /\\brefactor\\b/i,\n /\\bcleanup\\b/i\n];\n\nreturn items.filter(item => {\n const title = item.json.title || \"\";\n\n const isIgnored = ignoredTitlePatterns.some(\n pattern => pattern.test(title)\n );\n\n return !isIgnored;\n});"
},
"typeVersion": 2
},
{
"id": "c3527110-5ff1-461b-88aa-e82328f0dffe",
"name": "Standardize Release Format",
"type": "n8n-nodes-base.code",
"position": [
1568,
352
],
"parameters": {
"jsCode": "return items.map(item => {\n const data = item.json;\n\n return {\n json: {\n title: data.title || \"Untitled release\",\n\n link:\n data.link ||\n data.guid ||\n data.url ||\n \"#\",\n\n summary:\n data.contentSnippet ||\n data.description ||\n data.content ||\n \"\",\n\n published:\n data.isoDate ||\n data.pubDate ||\n data.published ||\n null,\n\n meta: {\n ...(data.meta || {})\n }\n }\n };\n});"
},
"typeVersion": 2
},
{
"id": "fa9ccf62-a5c1-4478-bd6b-0380dc6d649a",
"name": "Group by Release Category",
"type": "n8n-nodes-base.code",
"position": [
1792,
352
],
"parameters": {
"jsCode": "const groups = {};\n\nfor (const item of items) {\n const category =\n item.json.meta?.category || \"Other\";\n\n if (!groups[category]) {\n groups[category] = [];\n }\n\n groups[category].push(item.json);\n}\n\nreturn [\n {\n json: {\n groups\n }\n }\n];"
},
"typeVersion": 2
},
{
"id": "056eba0d-2caf-4ed8-bb64-aca7461a2f09",
"name": "Create HTML Newsletter",
"type": "n8n-nodes-base.code",
"position": [
2016,
352
],
"parameters": {
"jsCode": "const groups = items[0].json.groups;\n\nconst MAX_SUMMARY_LENGTH = 250;\n\nfunction truncate(text, maxLength) {\n if (!text) return \"\";\n\n // Strip HTML tags from RSS summaries\n const clean = text.replace(/<[^>]*>/g, \"\").trim();\n\n if (clean.length <= maxLength) {\n return clean;\n }\n\n return clean.substring(0, maxLength).trim() + \"...\";\n}\n\nlet html = `\n<!DOCTYPE html>\n<html>\n<body style=\"\n margin:0;\n padding:0;\n background:#F7F3EE;\n font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Arial,sans-serif;\n color:#1C1B19;\n\">\n\n<table width=\"100%\" cellpadding=\"0\" cellspacing=\"0\">\n<tr>\n<td align=\"center\" style=\"padding:32px 16px;\">\n\n<table width=\"700\" cellpadding=\"0\" cellspacing=\"0\" style=\"\n background:#FFFFFF;\n border-radius:16px;\n overflow:hidden;\n padding:32px;\n\">\n\n<tr>\n<td>\n\n<h1 style=\"\n margin:0;\n font-size:28px;\n color:#1C1B19;\n\">\n\ud83d\ude80 Developer Release Digest\n</h1>\n\n<p style=\"\n color:#6B625A;\n font-size:14px;\n margin-top:8px;\n\">\n${new Date().toLocaleDateString(\"en-BE\")}\n</p>\n\n<hr style=\"\n border:none;\n border-top:1px solid #E8DED4;\n margin:24px 0;\n\">\n`;\n\nfor (const [category, releases] of Object.entries(groups)) {\n\n html += `\n <h2 style=\"\n color:#D97757;\n font-size:20px;\n margin-top:32px;\n margin-bottom:16px;\n \">\n ${category}\n </h2>\n `;\n\n for (const release of releases.slice(0, 5)) {\n\n html += `\n <div style=\"\n background:#FAF9F5;\n border-radius:12px;\n padding:16px;\n margin-bottom:16px;\n \">\n\n <h3 style=\"\n margin:0 0 8px 0;\n font-size:16px;\n color:#1C1B19;\n \">\n ${release.title}\n </h3>\n\n <p style=\"\n margin:0 0 12px 0;\n color:#4B4540;\n font-size:14px;\n line-height:1.5;\n \">\n ${truncate(release.summary, MAX_SUMMARY_LENGTH)}\n </p>\n\n <p style=\"\n margin:0;\n font-size:13px;\n color:#8A8178;\n \">\n ${release.meta.source}\n </p>\n\n <a href=\"${release.link}\" style=\"\n display:inline-block;\n margin-top:12px;\n padding:8px 14px;\n background:#D97757;\n color:#FFFFFF;\n text-decoration:none;\n border-radius:8px;\n font-size:14px;\n \">\n Read More \u2192\n </a>\n\n </div>\n `;\n }\n}\n\nhtml += `\n</td>\n</tr>\n\n</table>\n\n</td>\n</tr>\n</table>\n\n</body>\n</html>\n`;\n\nreturn [\n {\n json: {\n html,\n hasReleases: Object.values(groups).some(\n releases => releases.length > 0\n )\n }\n }\n];"
},
"typeVersion": 2
},
{
"id": "b09f3224-3a65-410c-b98f-6bb8cc075b79",
"name": "Dispatch Email Notification",
"type": "n8n-nodes-resend.resend",
"position": [
2464,
352
],
"parameters": {
"to": "user@example.com",
"from": "Developer Digest <user@example.com>",
"html": "={{$json.html}}",
"subject": "=\ud83d\ude80 Developer Release Digest - {{$now.format('yyyy-MM-dd')}}",
"authentication": "apiKey",
"additionalOptions": {}
},
"credentials": {
"resendApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "f7a588c6-d86d-4741-ad8a-6bc6be6fa744",
"name": "Check for Available Releases",
"type": "n8n-nodes-base.if",
"position": [
2240,
352
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "f83d280b-c48f-4ab0-a7f1-1440b90da048",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
},
"leftValue": "={{ $json.hasReleases }}",
"rightValue": ""
}
]
}
},
"typeVersion": 2.3
},
{
"id": "0b9c0733-2f63-4cd7-b149-8b3089476cfe",
"name": "Compile RSS Sources",
"type": "n8n-nodes-base.code",
"position": [
224,
352
],
"parameters": {
"jsCode": "const feeds = [\n {\n url: 'https://blog.jetbrains.com/feed/',\n category: 'Developer Tools',\n source: 'JetBrains Blog'\n },\n {\n url: 'https://github.com/gradle/gradle/releases.atom',\n category: 'Developer Tools',\n source: 'Gradle Releases'\n },\n {\n url: 'https://android-developers.googleblog.com/feeds/posts/default',\n category: 'Android',\n source: 'Android Developers Blog'\n },\n {\n url: 'https://github.com/JetBrains/kotlin/releases.atom',\n category: 'Kotlin',\n source: 'Kotlin Releases'\n },\n {\n url: 'https://blog.jetbrains.com/kotlin/feed/',\n category: 'Kotlin',\n source: 'Kotlin Blog'\n },\n {\n url: 'https://aws.amazon.com/about-aws/whats-new/recent/feed/',\n category: 'Cloud',\n source: 'AWS What\u2019s New'\n },\n {\n url: 'https://openai.com/blog/rss.xml',\n category: 'AI',\n source: 'OpenAI Blog'\n },\n {\n url: 'https://openai.com/news/rss.xml',\n category: 'AI',\n source: 'OpenAI News'\n },\n {\n url: 'https://rsshub.bestblogs.dev/anthropic/news',\n category: 'AI',\n source: 'Anthropic News'\n }\n];\n\n// Return them as individual n8n items\nreturn feeds.map(feed => ({ json: feed }));"
},
"typeVersion": 2
},
{
"id": "87e5fdc3-881e-4381-a4af-1c0082431e92",
"name": "Set Release Metadata",
"type": "n8n-nodes-base.set",
"position": [
672,
352
],
"parameters": {
"mode": "raw",
"options": {},
"jsonOutput": "={\n \"meta\": {\n \"category\": \"{{ $('Compile RSS Sources').item.json.category }}\",\n \"source\": \"{{ $('Compile RSS Sources').item.json.source }}\",\n \"fetchedAt\": \"{{ $now.toISO() }}\"\n }\n}",
"includeOtherFields": true
},
"typeVersion": 3.4
},
{
"id": "419e054c-29e6-455b-8d8d-0a4aca0949ab",
"name": "Retrieve RSS Feed Data",
"type": "n8n-nodes-base.rssFeedRead",
"position": [
448,
352
],
"parameters": {
"url": "={{ $json.url }}",
"options": {}
},
"typeVersion": 1.2
}
],
"active": true,
"settings": {
"binaryMode": "separate",
"callerPolicy": "workflowsFromSameOwner",
"timeSavedMode": "fixed",
"availableInMCP": false,
"executionOrder": "v1"
},
"versionId": "08205c1f-a751-46d7-8c08-fdb0186398bd",
"nodeGroups": [],
"connections": {
"Compile RSS Sources": {
"main": [
[
{
"node": "Retrieve RSS Feed Data",
"type": "main",
"index": 0
}
]
]
},
"Every Monday at 9am": {
"main": [
[
{
"node": "Compile RSS Sources",
"type": "main",
"index": 0
}
]
]
},
"Set Release Metadata": {
"main": [
[
{
"node": "Select Recent Releases",
"type": "main",
"index": 0
}
]
]
},
"Create HTML Newsletter": {
"main": [
[
{
"node": "Check for Available Releases",
"type": "main",
"index": 0
}
]
]
},
"Retrieve RSS Feed Data": {
"main": [
[
{
"node": "Set Release Metadata",
"type": "main",
"index": 0
}
]
]
},
"Select Recent Releases": {
"main": [
[
{
"node": "Exclude Non-Stable Releases",
"type": "main",
"index": 0
}
]
]
},
"Remove Irrelevant Words": {
"main": [
[
{
"node": "Standardize Release Format",
"type": "main",
"index": 0
}
]
]
},
"Group by Release Category": {
"main": [
[
{
"node": "Create HTML Newsletter",
"type": "main",
"index": 0
}
]
]
},
"Standardize Release Format": {
"main": [
[
{
"node": "Group by Release Category",
"type": "main",
"index": 0
}
]
]
},
"Exclude Non-Stable Releases": {
"main": [
[
{
"node": "Remove Irrelevant Words",
"type": "main",
"index": 0
}
]
]
},
"Check for Available Releases": {
"main": [
[
{
"node": "Dispatch Email Notification",
"type": "main",
"index": 0
}
]
]
}
}
}
Credentials you'll need
Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.
resendApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This workflow runs weekly to collect recent release and news items from multiple developer-focused RSS/Atom feeds, filters out noisy and dev-build entries, groups the remaining items by category, and sends an HTML digest email via Resend. Runs on a weekly schedule (Monday at…
Source: https://n8n.io/workflows/17340/ — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
Wait Code. Uses scheduleTrigger, markdown, splitInBatches, rssFeedRead. Scheduled trigger; 23 nodes.
Simple workflow to get NASA APOD each day in your mail inbox, using the official RSS feed and a SMTP Node to use the server that you want (We recommend using GMAIL as it's free and simple to get an AP
Weekly Real Estate 12-Pack (Sunday 10am ET). Uses rssFeedRead, emailSend. Scheduled trigger; 10 nodes.
post to mattermost v2. Uses rssFeedRead, httpRequest, noOp. Scheduled trigger; 6 nodes.
Daily RSS → Email Digest. Uses rssFeedRead, emailSend. Scheduled trigger; 5 nodes.