Building a daily AI-curated newsletter with n8n and Claude: RSS ingestion, relevance scoring, and plain-text delivery via Resend
A daily AI-curated newsletter can run unattended in n8n — RSS ingestion, Claude relevance scoring, and Resend plain-text delivery in a 5-node workflow. Heres the complete setup.
A daily AI-curated newsletter that surfaces relevant content from multiple RSS feeds is a three-part problem: ingest, score, and deliver. n8n handles the scheduling and integrations; Claude handles the relevance judgment.
Architecture
Five nodes, running daily at 06:00:
1. Schedule Trigger — fires once daily, no configuration needed
2. HTTP Request — fetches 3-5 RSS feeds as raw XML using GET requests
3. Code node — parses XML to JavaScript objects, extracts title, link, pubDate, description; filters to items published in the last 24 hours
4. AI Agent (Claude) — passes each item to Claude with a system prompt defining the newsletter topic and scoring rubric; returns score + one-line summary as JSON
5. Resend node — assembles the filtered, scored items into a plain-text email body and sends via Resend API
Claude scoring prompt
The system prompt defines the newsletter's scope once:
`
You are a content curator for [newsletter name], a daily digest for [target reader] focused on [topic].
Score each article for relevance on a scale of 1-10, where 10 is directly on-topic and actionable,
and 1 is tangentially related or too general. Return JSON: {"score": number, "summary": "one sentence"}.
`
The user prompt passes the article title and description. After the Claude node, an IF node filters out items with score below 7 (adjust threshold based on feed quality and desired newsletter length).
Prompt caching
The system prompt is static — same for every item in the same run. Add cache_control: {type: "ephemeral"} to the system prompt message block. Claude caches the processed prompt for 5 minutes (long enough for a single workflow run processing 50-100 items). At Haiku pricing, this saves ~$0.05-0.08 per day at 100 items.
Resend delivery
Build the email body in a Code node after filtering:
`javascript
const items = $input.all();
const lines = items.map(i => • ${i.json.summary}\n ${i.json.link}).join('\n\n');
return [{ json: { subject: Daily digest — ${new Date().toDateString()}, text: lines } }];
`
Pass subject and text to the Resend node. Plain text avoids email client rendering issues and improves deliverability compared to HTML-heavy templates.
Threshold tuning
The score threshold is the most important parameter. Start at 7, run for a week, and read the output:
The scoring prompt's phrasing matters more than the number. "Directly actionable for a solo operator" selects different content than "technically interesting for developers" even on the same feeds.
FAQ
Can I use the n8n Claude integration directly instead of the HTTP Request node?
Yes — n8n has a native Claude AI node. The HTTP Request approach gives more control over the raw API call (including cache_control headers for prompt caching, which the native node doesn't expose as of May 2026).
What RSS feeds work best?
The system is feed-agnostic. Technical newsletters, industry blogs, and Substack RSS feeds (append /feed to any Substack URL) all work. Avoid feeds that only include descriptions without full content — scoring works better with a complete article description.
How do I handle feeds with no new items?
The Code node that filters to last-24-hours items returns an empty array when no new items exist. Add an IF node after the filter: items.length > 0 routes to Claude; the false branch routes to a Stop And Error or a log comment. An empty newsletter feels like an error to subscribers — better to skip the send entirely.