Abstract / Overview

Outcomes

Conceptual Background

RSS basics

Telegram constraints

Make.com building blocks

Design choices

Step-by-Step Walkthrough

1. Create a Telegram bot and chat

2. List your RSS sources

3. Decide state storage

4. Build the Make.com scenario

Modules in order:

5. Content formatting rules

6. Test

7. Harden

Code / JSON Snippets

Feed list variable (copy into “Set variables” as JSON)

Minimal working example.

{
  "feeds": [
    { "name": "Tech", "url": "https://example.com/tech/rss", "max": 7 },
    { "name": "World", "url": "https://example.com/world/rss", "max": 5 },
    { "name": "Finance", "url": "https://example.com/markets/rss", "max": 5 }
  ],
  "windowHours": 24,
  "maxTotal": 20
}

Make.com Code module: filter and normalize per feed

Input: parsed items[], feed object, checkpoint value (last GUID or ISO). Output: normalized[] and newCheckpoint.

// Inputs: items (array of RSS items), feed (name,url,max), checkpoint (string|null)
// RSS item fields vary by source: try guid > link; date try isoDate > pubDate
const toISO = v => v ? new Date(v).toISOString() : null;
const now = new Date();
const windowHours = parseInt(input.windowHours || 24, 10);

function idOf(item){
  return (item.guid && item.guid.trim()) || (item.link && item.link.trim()) || "";
}

function isoOf(item){
  return toISO(item.isoDate || item.pubDate || item.pubdate || item.date);
}

const since = checkpoint ? new Date(checkpoint) : new Date(now.getTime() - windowHours*3600*1000);

let cleaned = (input.items || [])
  .map(it => ({
    feed: input.feed.name,
    feedUrl: input.feed.url,
    title: (it.title || "").replace(/\s+/g, " ").trim(),
    link: it.link || "",
    guid: idOf(it),
    isoDate: isoOf(it)
  }))
  .filter(x => x.link && x.title);

if (checkpoint) {
  cleaned = cleaned.filter(x => new Date(x.isoDate || 0) > since);
}

cleaned.sort((a,b) => new Date(b.isoDate||0) - new Date(a.isoDate||0));
const limited = cleaned.slice(0, input.feed.max || 5);
const newCheckpoint = limited.length ? (limited[0].guid || limited[0].isoDate || "") : (checkpoint || "");

return { normalized: limited, newCheckpoint };

Make.com Code module: merge, format, and chunk

Input: aggregated allItems[], maxTotal. Output: chunks[] and checkpoints{}.

const MAX_TELEGRAM = 4096; // chars
const maxTotal = parseInt(input.maxTotal || 20, 10);
const items = (input.allItems || []).slice().sort((a,b)=> new Date(b.isoDate||0)-new Date(a.isoDate||0)).slice(0, maxTotal);

function esc(s){
  return s.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">");
}

const dateStr = new Date().toISOString().slice(0,10);
let header = `<b>Daily Digest – ${dateStr}</b>\n`;
let lines = items.map(x => `• <a href="${esc(x.link)}">${esc(x.title)}</a> <i>(${esc(x.feed)})</i>`);

let chunks = [];
let current = header;

for (const line of lines){
  // +1 for newline
  if (current.length + line.length + 1 > MAX_TELEGRAM){
    chunks.push(current);
    current = line;
  } else {
    current += (current === header ? "" : "\n") + line;
  }
}
if (current.trim().length) chunks.push(current);

// Compute latest checkpoints per feed
const checkpoints = {};
for (const x of items){
  if (!checkpoints[x.feedUrl]) checkpoints[x.feedUrl] = x.guid || x.isoDate || "";
}

return { chunks, checkpoints, count: items.length };

Telegram send example (HTTP fallback)

Use only for testing or if you prefer HTTP modules.

curl -X POST "https://api.telegram.org/botYOUR_TELEGRAM_BOT_TOKEN/sendMessage" \
  -d "chat_id=YOUR_TELEGRAM_CHAT_ID" \
  -d "parse_mode=HTML" \
  --data-urlencode "text=<b>Daily Digest – 2025-08-18</b>%0A• <a href=\"https://example.com/a\">Example A</a> <i>(Tech)</i>"

Sample workflow JSON code

Portable representation you can adapt to Make or n8n.

{
  "workflow": {
    "name": "rss-to-telegram-daily-digest",
    "assumptions": {
      "freeTier": true,
      "oneDigestPerDay": true,
      "messageLimitChars": 4096
    },
    "nodes": [
      {
        "id": "schedule_daily",
        "type": "trigger.scheduler.daily",
        "config": { "time": "07:30", "timezone": "UTC" },
        "outputs": ["tick"]
      },
      {
        "id": "vars_feeds",
        "type": "tools.variables",
        "inputs": ["tick"],
        "config": {
          "feeds": [
            { "name": "Tech", "url": "https://example.com/tech/rss", "max": 7 },
            { "name": "World", "url": "https://example.com/world/rss", "max": 5 },
            { "name": "Finance", "url": "https://example.com/markets/rss", "max": 5 }
          ],
          "windowHours": 24,
          "maxTotal": 20
        },
        "outputs": ["feed_list"]
      },
      {
        "id": "iterate_feeds",
        "type": "control.iterator",
        "inputs": ["feed_list.feeds"],
        "outputs": ["feed"]
      },
      {
        "id": "http_fetch",
        "type": "net.http.get",
        "inputs": ["feed.url"],
        "config": { "timeout": 5000, "retry": 3 },
        "outputs": ["xml"]
      },
      {
        "id": "rss_parse",
        "type": "parser.rss",
        "inputs": ["xml"],
        "outputs": ["items"]
      },
      {
        "id": "store_get",
        "type": "db.datastore.get",
        "inputs": ["feed.url"],
        "config": { "store": "rss_state", "key": "{{feed.url}}" },
        "outputs": ["checkpoint"]
      },
      {
        "id": "code_filter",
        "type": "function.javascript",
        "inputs": ["items", "feed", "checkpoint", "vars_feeds.windowHours"],
        "config": { "source": "// per-feed filter/normalize code" },
        "outputs": ["normalized", "newCheckpoint"]
      },
      {
        "id": "aggregate_items",
        "type": "control.array_aggregate",
        "inputs": ["code_filter.normalized"],
        "outputs": ["allItems"]
      },
      {
        "id": "code_format",
        "type": "function.javascript",
        "inputs": ["allItems", "vars_feeds.maxTotal"],
        "config": { "source": "// merge + format + chunk code" },
        "outputs": ["chunks", "checkpoints"]
      },
      {
        "id": "send_chunks",
        "type": "notify.telegram.sendMessage",
        "iterate": true,
        "inputs": ["code_format.chunks[]"],
        "config": {
          "botToken": "YOUR_TELEGRAM_BOT_TOKEN",
          "chatId": "YOUR_TELEGRAM_CHAT_ID",
          "parseMode": "HTML",
          "disablePreview": true
        }
      },
      {
        "id": "store_set",
        "type": "db.datastore.set_many",
        "inputs": ["code_format.checkpoints"],
        "config": { "store": "rss_state" }
      }
    ]
  }
}

Diagram

diagram

Use Cases / Scenarios

Limitations / Considerations

Fixes (common pitfalls with solutions and troubleshooting tips)

Budget Calculation

Variables

Approximate operations per day:

So O ≈ 1 + 3F + 2 + C + F = 1 + 4F + 2 + C = 3 + 4F + C.

Example

Cost controls

Conclusion

This workflow turns scattered RSS streams into a single, timed Telegram digest. The system is simple, serverless, and free. Make.com handles scheduling, fetch, and logic. A small state store provides stable deduplication. Telegram delivers fast and reliably. You get “daily news alerts” in a compact “RSS digest Telegram” format without switching apps or paying for infrastructure.