This workflow corresponds to n8n.io template #17507 — 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": "6c34e8d4-725c-4a74-909f-e2a1c3fe3421",
"meta": {
"templateCredsSetupCompleted": false
},
"name": "Send a coffee newsletter at 09:00 local time in every region",
"tags": [],
"nodes": [
{
"id": "2abf1afd-e8b8-4b84-93cd-68c4d5ea61e6",
"name": "At 09:00 in each target timezone",
"type": "@rrulenet/n8n-nodes-rrulenet.rruleNetScheduleTrigger",
"position": [
-920,
-80
],
"parameters": {
"name": "Morning coffee newsletter",
"input": "Send the morning coffee newsletter every day at 9am local time in Paris, New York, Tokyo, and Perth",
"timezone": "UTC",
"onDeactivate": "pause"
},
"typeVersion": 1
},
{
"id": "d56ca913-fa14-4d76-a7ba-fbe797861d89",
"name": "When clicking 'Execute workflow'",
"type": "n8n-nodes-base.manualTrigger",
"position": [
-920,
240
],
"parameters": {},
"typeVersion": 1
},
{
"id": "d4d03c2b-f38d-4c8d-8f35-d8ef05a0f4da",
"name": "Use a sample Paris execution",
"type": "n8n-nodes-base.set",
"position": [
-680,
240
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "sample-schedule-id",
"name": "schedule_id",
"type": "string",
"value": "manual-preview"
},
{
"id": "sample-schedule-name",
"name": "schedule_name",
"type": "string",
"value": "Morning coffee newsletter preview"
},
{
"id": "sample-execution-id",
"name": "execution_id",
"type": "string",
"value": "manual-preview-paris"
},
{
"id": "sample-scheduled-for",
"name": "scheduled_for",
"type": "string",
"value": "={{ $now.setZone('Europe/Paris').toISO() }}"
},
{
"id": "sample-timezone",
"name": "timezone",
"type": "string",
"value": "Europe/Paris"
},
{
"id": "sample-target-id",
"name": "target_id",
"type": "string",
"value": "paris"
},
{
"id": "sample-target-label",
"name": "target_label",
"type": "string",
"value": "Paris"
},
{
"id": "sample-target-timezone",
"name": "target_timezone",
"type": "string",
"value": "Europe/Paris"
},
{
"id": "sample-target-metadata",
"name": "target_metadata",
"type": "object",
"value": "={{ { city: 'Paris', timezone: 'Europe/Paris', preview: true } }}"
},
{
"id": "sample-input-type",
"name": "input_type",
"type": "string",
"value": "manual-preview"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "e9b540fb-e2aa-47a8-b87e-0cde5259dbb8",
"name": "Configure regional audiences",
"type": "n8n-nodes-base.code",
"position": [
-440,
-80
],
"parameters": {
"jsCode": "// Replace every example.com address before publishing the workflow.\nconst shared = {\n sender: 'Coffee Newsletter <user@example.com>',\n feed_url: 'https://news.ycombinator.com/rss',\n max_articles: 5,\n};\n\nconst audiences = {\n paris: {\n timezone: 'Europe/Paris',\n locale: 'fr-FR',\n recipient: 'user@example.com',\n greeting: 'Bonjour Paris',\n subject_prefix: 'Votre pause caf\u00e9',\n intro: 'Voici les articles \u00e0 d\u00e9couvrir avec votre caf\u00e9 ce matin.',\n footer: 'Envoy\u00e9 \u00e0 09:00 heure locale gr\u00e2ce \u00e0 rrule.net et n8n.',\n },\n new_york: {\n timezone: 'America/New_York',\n locale: 'en-US',\n recipient: 'user@example.com',\n greeting: 'Good morning New York',\n subject_prefix: 'Your morning coffee',\n intro: 'Here are a few stories to explore with your coffee this morning.',\n footer: 'Delivered at 09:00 local time with rrule.net and n8n.',\n },\n tokyo: {\n timezone: 'Asia/Tokyo',\n locale: 'ja-JP',\n recipient: 'user@example.com',\n greeting: '\u304a\u306f\u3088\u3046\u3054\u3056\u3044\u307e\u3059\u3001\u6771\u4eac',\n subject_prefix: '\u671d\u306e\u30b3\u30fc\u30d2\u30fc\u30cb\u30e5\u30fc\u30b9',\n intro: '\u4eca\u671d\u306e\u30b3\u30fc\u30d2\u30fc\u3068\u4e00\u7dd2\u306b\u8aad\u307f\u305f\u3044\u8a18\u4e8b\u3092\u304a\u5c4a\u3051\u3057\u307e\u3059\u3002',\n footer: 'rrule.net \u3068 n8n \u306b\u3088\u308a\u73fe\u5730\u6642\u959309:00\u306b\u914d\u4fe1\u3055\u308c\u307e\u3057\u305f\u3002',\n },\n perth: {\n timezone: 'Australia/Perth',\n locale: 'en-AU',\n recipient: 'user@example.com',\n greeting: 'Good morning Perth',\n subject_prefix: 'Your morning coffee',\n intro: 'Here are a few stories to explore with your coffee this morning.',\n footer: 'Delivered at 09:00 local time with rrule.net and n8n.',\n },\n};\n\nreturn $input.all().map((item, itemIndex) => {\n const targetId = String(item.json.target_id ?? '');\n const audience = audiences[targetId];\n\n if (!audience) {\n throw new Error(`No audience configuration exists for target_id ${targetId}. Update the audiences map before publishing.`);\n }\n\n if (item.json.target_timezone && item.json.target_timezone !== audience.timezone) {\n throw new Error(`Unexpected timezone ${item.json.target_timezone} for target_id ${targetId}. Expected ${audience.timezone}.`);\n }\n\n return {\n json: {\n ...item.json,\n ...shared,\n ...audience,\n },\n pairedItem: { item: itemIndex },\n };\n});"
},
"typeVersion": 2
},
{
"id": "18d2e9cc-ca89-4ecf-990a-2a1b08b093b8",
"name": "Read the morning RSS feed",
"type": "n8n-nodes-base.rssFeedRead",
"maxTries": 3,
"position": [
-180,
-80
],
"parameters": {
"url": "={{ $json.feed_url }}",
"options": {}
},
"retryOnFail": true,
"typeVersion": 1.2,
"waitBetweenTries": 5000
},
{
"id": "636484f7-bd90-4615-b6b3-f54e54d64227",
"name": "Build localized newsletter",
"type": "n8n-nodes-base.code",
"position": [
80,
-80
],
"parameters": {
"jsCode": "const config = $('Configure regional audiences').first().json;\n\nconst escapeHtml = (value) => String(value ?? '')\n .replaceAll('&', '&')\n .replaceAll('<', '<')\n .replaceAll('>', '>')\n .replaceAll('\\\"', '"')\n .replaceAll(\"'\", ''');\n\nconst safeUrl = (value) => {\n const url = String(value ?? '').trim();\n return /^https?:\\/\\/[^\\s<>\"']+$/i.test(url) ? url : '#';\n};\n\nconst articleLimit = Math.max(1, Math.min(10, Number(config.max_articles) || 5));\nconst articles = $input.all()\n .map((item) => item.json)\n .filter((article) => typeof article.title === 'string' && typeof article.link === 'string')\n .slice(0, articleLimit);\n\nif (articles.length === 0) {\n throw new Error('The RSS feed returned no usable articles. Check feed_url before publishing.');\n}\n\nconst scheduledDate = new Date(String(config.scheduled_for || new Date().toISOString()));\nconst displayDate = new Intl.DateTimeFormat(String(config.locale), {\n dateStyle: 'full',\n timeZone: String(config.timezone),\n}).format(scheduledDate);\n\nconst articleHtml = articles.map((article) => {\n const title = escapeHtml(article.title);\n const link = escapeHtml(safeUrl(article.link));\n const rawSnippet = String(article.contentSnippet ?? '').trim();\n const snippet = /^Article URL:/i.test(rawSnippet) ? '' : escapeHtml(rawSnippet.slice(0, 240));\n const description = snippet ? `<p style=\\\"margin:8px 0 0;color:#5f5149;font-size:14px;font-weight:400;line-height:1.5;\\\">${snippet}</p>` : '';\n return `<li style=\\\"margin:0 0 22px;padding-left:4px;color:#6f3f21;font-size:17px;font-weight:700;line-height:1.4;\\\"><a href=\\\"${link}\\\" style=\\\"color:#6f3f21;font-size:17px;font-weight:700;line-height:1.4;text-decoration:none;\\\">${title}</a>${description}</li>`;\n}).join('');\n\nconst html = `<!doctype html>\n<html lang=\\\"${escapeHtml(String(config.locale).split('-')[0] || 'en')}\\\">\n <head>\n <meta charset=\\\"utf-8\\\">\n <meta name=\\\"viewport\\\" content=\\\"width=device-width,initial-scale=1\\\">\n </head>\n <body style=\\\"margin:0;background:#f7f1eb;font-family:Arial,sans-serif;color:#2d241f;\\\">\n <div style=\\\"display:none;max-height:0;overflow:hidden;opacity:0;color:transparent;\\\">${escapeHtml(config.intro)}</div>\n <table role=\\\"presentation\\\" width=\\\"100%\\\" cellspacing=\\\"0\\\" cellpadding=\\\"0\\\" style=\\\"background:#f7f1eb;padding:24px 12px;\\\">\n <tr><td align=\\\"center\\\">\n <table role=\\\"presentation\\\" width=\\\"100%\\\" cellspacing=\\\"0\\\" cellpadding=\\\"0\\\" style=\\\"max-width:640px;background:#ffffff;border-radius:14px;overflow:hidden;\\\">\n <tr><td style=\\\"background:#5b3825;padding:28px 32px;color:#ffffff;\\\">\n <div style=\\\"font-size:13px;letter-spacing:.08em;text-transform:uppercase;opacity:.8;\\\">${escapeHtml(displayDate)}</div>\n <h1 style=\\\"margin:10px 0 0;font-size:28px;\\\">\u2615 ${escapeHtml(config.greeting)}</h1>\n </td></tr>\n <tr><td style=\\\"padding:30px 32px;\\\">\n <p style=\\\"margin:0 0 24px;font-size:16px;line-height:1.6;\\\">${escapeHtml(config.intro)}</p>\n <ol style=\\\"margin:0;padding-left:24px;\\\">${articleHtml}</ol>\n </td></tr>\n <tr><td style=\\\"padding:20px 32px;background:#efe3d7;color:#6b5a50;font-size:12px;line-height:1.5;\\\">\n ${escapeHtml(config.footer)}<br>Target: ${escapeHtml(config.target_id)} \u00b7 ${escapeHtml(config.target_timezone)}\n </td></tr>\n </table>\n </td></tr>\n </table>\n </body>\n</html>`;\n\nreturn [{\n json: {\n execution_id: config.execution_id,\n scheduled_for: config.scheduled_for,\n target_id: config.target_id,\n target_timezone: config.target_timezone,\n recipient: config.recipient,\n sender: config.sender,\n subject: `${config.subject_prefix} \u2014 ${displayDate}`,\n html,\n article_count: articles.length,\n },\n}];"
},
"typeVersion": 2
},
{
"id": "33bf7781-5b92-4105-aaed-78de5b3863e0",
"name": "Send with Brevo",
"type": "n8n-nodes-base.sendInBlue",
"position": [
340,
-80
],
"parameters": {
"sender": "={{ $json.sender }}",
"subject": "={{ $json.subject }}",
"resource": "email",
"sendHTML": true,
"operation": "send",
"htmlContent": "={{ $json.html }}",
"receipients": "={{ $json.recipient }}",
"additionalFields": {
"emailTags": {
"tags": {
"tag": "rrulenet,coffee-newsletter"
}
}
}
},
"typeVersion": 1
},
{
"id": "19ad56f4-4a2f-411e-90e5-96703e00234c",
"name": "Return delivery context",
"type": "n8n-nodes-base.set",
"position": [
600,
-80
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "result-message-id",
"name": "message_id",
"type": "string",
"value": "={{ $json.messageId }}"
},
{
"id": "result-execution-id",
"name": "execution_id",
"type": "string",
"value": "={{ $('Build localized newsletter').first().json.execution_id }}"
},
{
"id": "result-scheduled-for",
"name": "scheduled_for",
"type": "string",
"value": "={{ $('Build localized newsletter').first().json.scheduled_for }}"
},
{
"id": "result-target-id",
"name": "target_id",
"type": "string",
"value": "={{ $('Build localized newsletter').first().json.target_id }}"
},
{
"id": "result-target-timezone",
"name": "target_timezone",
"type": "string",
"value": "={{ $('Build localized newsletter').first().json.target_timezone }}"
},
{
"id": "result-recipient",
"name": "recipient",
"type": "string",
"value": "={{ $('Build localized newsletter').first().json.recipient }}"
},
{
"id": "result-article-count",
"name": "article_count",
"type": "number",
"value": "={{ $('Build localized newsletter').first().json.article_count }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "34284232-2ab6-457d-a5b9-38d5adc34be0",
"name": "Workflow guide",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1560,
-400
],
"parameters": {
"width": 480,
"height": 880,
"content": "## Coffee newsletters at 09:00 local time\n\nThis workflow uses one target-aware rrule.net schedule to send a localized morning digest in Paris, New York, Tokyo, and Perth.\n\n### Before activation\n\n1. Install `@rrulenet/n8n-nodes-rrulenet` version 0.1.4 or later.\n2. Add rrule.net and Brevo credentials.\n3. In **Configure regional audiences**, replace the example sender and recipients.\n4. Optionally change the RSS feed and article limit in the same node.\n5. Run **When clicking 'Execute workflow'** to test the Paris preview.\n6. Check the email and links, then activate the workflow.\n\n### Customize\n\nAdd targets and matching audience entries, replace the RSS source, adapt the localized copy and branding, or swap Brevo for another email provider."
},
"typeVersion": 1
},
{
"id": "3ade7f99-6a40-4a0c-8868-506081861f66",
"name": "Target-aware schedule",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1040,
-400
],
"parameters": {
"color": 7,
"width": 320,
"height": 440,
"content": "## One schedule, four local times\n\n**At 09:00 in each target timezone** creates one logical rrule.net schedule with four targets. Paris and New York stay at 09:00 through DST changes; Tokyo and Perth keep their non-DST offsets. Each execution carries `target_id` and `target_timezone` for deterministic routing."
},
"typeVersion": 1
},
{
"id": "d902b6ee-9e0b-456e-bcda-a2a888e3668e",
"name": "Manual preview",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1040,
40
],
"parameters": {
"color": 7,
"width": 560,
"height": 440,
"content": "## Safe manual preview\n\n**When clicking 'Execute workflow'** injects a sample Paris execution without changing the remote rrule.net schedule. After you configure credentials and real addresses, the preview sends a real email through Brevo."
},
"typeVersion": 1
},
{
"id": "34ffd0a9-a614-4d0d-92d7-c4485895a8d1",
"name": "Localized content",
"type": "n8n-nodes-base.stickyNote",
"position": [
-480,
-400
],
"parameters": {
"color": 7,
"width": 720,
"height": 440,
"content": "## Select, fetch, and localize\n\n**Configure regional audiences** matches `target_id` to its locale, timezone, sender, recipient, and localized copy. **Read the morning RSS feed** loads the configured source. **Build localized newsletter** keeps usable articles, escapes feed text, accepts only HTTP(S) links, and creates the responsive HTML email."
},
"typeVersion": 1
},
{
"id": "e90b268d-2f13-4fea-bf3b-4243bb55c334",
"name": "Delivery context",
"type": "n8n-nodes-base.stickyNote",
"position": [
288,
-400
],
"parameters": {
"color": 7,
"width": 448,
"height": 440,
"content": "## Send and return context\n\n**Send with Brevo** sends one digest for the current target. **Return delivery context** exposes the message ID, execution ID, scheduled time, target, recipient, and article count. Add the required consent, unsubscribe, and list-management behavior before public marketing use."
},
"typeVersion": 1
}
],
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "a9d67525-22b0-46e6-bd3f-41e031ebeb14",
"connections": {
"Send with Brevo": {
"main": [
[
{
"node": "Return delivery context",
"type": "main",
"index": 0
}
]
]
},
"Read the morning RSS feed": {
"main": [
[
{
"node": "Build localized newsletter",
"type": "main",
"index": 0
}
]
]
},
"Build localized newsletter": {
"main": [
[
{
"node": "Send with Brevo",
"type": "main",
"index": 0
}
]
]
},
"Configure regional audiences": {
"main": [
[
{
"node": "Read the morning RSS feed",
"type": "main",
"index": 0
}
]
]
},
"Use a sample Paris execution": {
"main": [
[
{
"node": "Configure regional audiences",
"type": "main",
"index": 0
}
]
]
},
"At 09:00 in each target timezone": {
"main": [
[
{
"node": "Configure regional audiences",
"type": "main",
"index": 0
}
]
]
},
"When clicking 'Execute workflow'": {
"main": [
[
{
"node": "Use a sample Paris execution",
"type": "main",
"index": 0
}
]
]
}
}
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Fetch an RSS feed, build a localized morning digest, and send it with Brevo at 09:00 local time in Paris, New York, Tokyo, and Perth from one target-aware rrule.net schedule. One rrule.net Schedule Trigger emits an execution at 09:00 in each configured target timezone. The…
Source: https://n8n.io/workflows/17507/ — 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.
Send a coffee newsletter at 09:00 local time in every region. Uses @rrulenet/n8n-nodes-rrulenet, rssFeedRead, sendInBlue. Scheduled trigger; 11 nodes.
This workflow runs hourly to read multiple RSS/Atom feeds, applies rule-based topic matching, relevance scoring, sentiment and entity tagging with deduplication, and then sends scored HTML email diges
World News Collector (10m). Uses rssFeedRead, dataTable. Scheduled trigger; 11 nodes.
Job Seeking. Uses scheduleTrigger, rssFeedRead, googleSheets, httpRequest. Scheduled trigger; 12 nodes.
Finance Alert. Uses rssFeedRead, openAi, httpRequest. Scheduled trigger; 11 nodes.