Open Source · MIT · Free Tier

Turn email newsletters into private RSS feeds

Self-hosted on Cloudflare Workers. Your data stays in your own account, served from your own domain.

Try the demo Self-host ↓ GitHub

Try it live — no setup required

A hosted instance runs at demo.kill-the.news, pre-loaded with sample feeds. Create a feed, grab the RSS URL, and add it to your reader — all without deploying anything.

URL demo.kill-the.news · Password password
Open demo Resets periodically · for testing only

Everything you need, nothing you don't

Built on serverless infrastructure — zero servers to maintain, no subscription fees.

Self-Hosted & Private

Your emails and feeds live exclusively in your own Cloudflare account. No shared infrastructure, no data mining.

Separate Address & Feed URL

Your subscribe address and your feed's reading URL are independent, unguessable ids. Share a feed without leaking the inbox that feeds it — and an address a newsletter harvests can never be turned into your feed.

Free Cloudflare Tier

Cloudflare Workers, KV, and Email Routing all fall within the generous free tier. Deploy at zero cost.

Your Own Domain

Subscribe to newsletters using addresses on your own domain (e.g. apple@yourdomain.com). No lock-in.

Two Ingestion Methods

Use Cloudflare Email Routing (no third-party) or ForwardEmail webhooks — whichever fits your setup.

Attachment Enclosures

Email attachments are stored in Cloudflare R2 and exposed as RSS enclosures — no extra hosting needed.

Per-Feed Icons

Each feed picks up the favicon of its newsletter's sender domain, so feeds are easy to tell apart in your reader and the admin UI.

Auto-Expiring Feeds

Give a feed a lifetime and it deletes itself when the timer runs out — perfect as a disposable inbox for one-off sign-ups you don't want to keep around.

Auto-Unsubscribe on Delete

Deleting a feed fires RFC 8058 one-click unsubscribe requests to its newsletters, so the messages stop arriving at the now-dead address.

Catch-All Fallback

Point your whole domain at kill-the-news: anything that isn't a feed is forwarded to a fallback address instead of dropped, so your personal mail still gets through.

External Auth Support

Optionally delegate admin authentication to Authelia, Authentik, or any reverse proxy that sets Remote-User.

REST API & OpenAPI

Automate feeds and emails through a versioned REST API, documented with an OpenAPI 3.1 spec and a live interactive reference.

RSS, Atom & JSON Feed

Every feed is served in all three formats — RSS 2.0, Atom, and JSON Feed — so it just works in NetNewsWire, Reeder, Feedly, NewsBlur and any other reader. Conditional requests (ETag / 304) keep polling cheap.

One-Click OPML Export

Export all your feeds as an OPML file and bulk-import them into any reader in one shot — easy onboarding, and no lock-in if you ever want to move.

Never Lose a Confirmation Link

kill-the-news detects "confirm your subscription" emails at ingestion and surfaces the link prominently in the admin — unlike kill-the-newsletter, where the confirm email lands buried in your feed reader and is easily missed.

Find the Source Feed

If a newsletter already publishes RSS, Atom, or JSON Feed, kill-the-news spots it and points you to the original — subscribe at the source directly when you prefer.

Three steps, done

From email delivery to your RSS reader in milliseconds, with no moving parts.

1

Subscribe with your address

Create a feed in the admin UI and get a unique address like newsletter.42@yourdomain.com. Subscribe to any newsletter with it.

2

Worker ingests the email

When a newsletter arrives, Cloudflare routes it to your Worker. It parses the content and stores it in KV — attachments go to R2.

3

Read in your RSS reader

Your feed is live at /rss/:feedId. Add it to any RSS client and never miss an issue.

Up and running in minutes

A single setup script handles KV namespaces, secrets, and wrangler.toml generation.

Terminal
# 1. Clone the repo
$ git clone https://github.com/juherr/kill-the-news.git && cd kill-the-news

# 2. Log in to Cloudflare
$ npx wrangler login

# 3. Run the interactive setup (creates KV, sets secrets, writes wrangler.toml)
$ bash setup.sh

# 4. Deploy to the edge
$ npm run deploy

Then choose how emails reach your Worker:

Alternative

ForwardEmail Webhook

Point ForwardEmail MX records at your domain. ForwardEmail parses incoming mail and POSTs a JSON payload to /api/inbound.

Deploy to Cloudflare

Everything you need to self-host kill-the-news on your own Cloudflare account, step by step.

1

Prerequisites

You need a free Cloudflare account with a domain managed by Cloudflare DNS, and Node.js ≥ 18.

  • Cloudflare account (free tier is enough)
  • A domain with DNS managed by Cloudflare
  • Node.js ≥ 18 & npm
  • Git
2

Clone & authenticate

Clone the repo and log in to Cloudflare via Wrangler. This opens a browser window to authorize the CLI.

Terminal
$ git clone https://github.com/juherr/kill-the-news.git
$ cd kill-the-news
$ npm install
$ npx wrangler login
3

Run the setup script

The interactive setup script creates the KV namespace, sets the admin password secret, and writes wrangler.toml for you.

Terminal
$ bash setup.sh

# The script will ask for:
#   - Your domain (e.g. newsletters.example.com)
#   - An admin password (stored as a Wrangler secret)
#   - Whether to enable R2 for attachments (optional)

This generates wrangler.toml from the example template. Do not commit it — it is gitignored.

4

Deploy the Worker

Terminal
$ npm run deploy

# Wrangler compiles the Worker, uploads it to Cloudflare,
# and prints the Worker URL. Your admin UI will be live at:
#   https://<your-domain>/admin
5

Configure email ingestion

Choose how incoming emails reach your Worker:

Cloudflare Email Routing

In the Cloudflare dashboard, go to Email → Email Routing and enable it on your domain. Add a catch-all rule with action Send to Worker pointing to your deployed Worker. No third-party service required.

Alternative

ForwardEmail Webhook

Point ForwardEmail MX records at your domain. ForwardEmail parses incoming mail and POSTs a JSON payload to /api/inbound. Useful if you already use ForwardEmail.

6

Optional: enable attachment storage

To store email attachments and expose them as RSS enclosures, create an R2 bucket and bind it in wrangler.toml:

wrangler.toml
[[r2_buckets]]
binding = "ATTACHMENT_BUCKET"
bucket_name = "kill-the-news-attachments"

Attachments will be served at /files/:id/:filename and linked as <enclosure> elements in the RSS feed.

7

Harden with WAF rate limiting

Protect your endpoints against abuse using Cloudflare WAF custom rate-limiting rules — no code changes required, pure infrastructure.

Via Cloudflare Dashboard

Go to Security → Security rules, click Create rule, choose Rate limiting rule, and create one rule per endpoint below.

⚠️ Free tier limitations: only 1 rate limiting rule allowed; period and block duration capped at 10 seconds. Prioritise the /api/inbound rule — it's the public-facing attack surface. Upgrade to a paid plan for full coverage.

Terraform

Via Terraform

Use cloudflare_ruleset with phase = "http_ratelimit" — see the snippet below.

Recommended limits:

WAF rules
Setting /api/inbound /admin*
Condition (URI Path) wildcard /api/inbound/* wildcard /admin/*
Limit (recommended) 60 req / min / IP 20 req / min / IP
Limit (free tier) 10 req / 10 s / IP 20 req / 10 s / IP
Action (recommended) Block (1 min) Managed Challenge (5 min)
Action (free tier) Block (10 s) Managed Challenge (10 s)

Terraform equivalent (supports method filtering and longer periods — requires a paid Cloudflare plan):

main.tf
resource "cloudflare_ruleset" "rate_limiting" {
  zone_id = var.cloudflare_zone_id
  name    = "kill-the-news rate limiting"
  kind    = "zone"
  phase   = "http_ratelimit"

  rules {
    description = "Rate limit /api/inbound"
    expression  = "(http.request.uri.path eq \"/api/inbound\" and http.request.method eq \"POST\")"
    action      = "block"
    ratelimit {
      characteristics     = ["ip.src"]
      period              = 60
      requests_per_period = 60
      mitigation_timeout  = 60
    }
  }

  rules {
    description = "Rate limit /admin"
    expression  = "starts_with(http.request.uri.path, \"/admin\")"
    action      = "managed_challenge"
    ratelimit {
      characteristics     = ["ip.src"]
      period              = 60
      requests_per_period = 20
      mitigation_timeout  = 300
    }
  }
}

These rules run at the Cloudflare edge before the Worker is invoked — zero latency impact on normal traffic. If ForwardEmail's delivery IPs ever trigger the /api/inbound limit, add them as an IP Access Rule with action Allow under Security → WAF → Tools.

Questions & answers

The practical stuff — subscribing, privacy, troubleshooting, and how kill-the-news differs.

How does kill-the-news work?

Create a feed in the admin UI and you get a unique address on your domain (e.g. newsletter.42@yourdomain.com) plus an RSS and an Atom feed. Any email sent to that address is turned into entries in those feeds.

How do I confirm a newsletter subscription?

Confirmation emails arrive as feed entries — open the entry in your reader and click the confirmation link. If a publisher requires a reply, subscribe with your normal inbox instead and set up a filter that auto-forwards its mail to your feed address.

Are my feeds private?

Yes. Each feed URL carries an unguessable ID, it is served from your own domain on your own Cloudflare account, and the admin UI is password-protected. Treat the feed URL like a password — anyone who has it can read your newsletters.

Why are old entries disappearing?

Feeds honor an optional size and time-to-live cap so RSS readers stay happy — some readers choke on feeds that grow too large. When a limit is reached, the oldest entries (and their R2 attachments) are purged automatically.

Can I share a feed with someone?

Don't. Anyone with the URL can read your newsletters and even unsubscribe you. Share the project instead, so others can self-host and create their own feeds.

Why isn't my feed updating?

Send a test email to the feed address. If it shows up within a minute, the delay is on the newsletter publisher's side, not kill-the-news. Readers that support WebSub get near-instant push updates instead of waiting for the next poll.

How is this different from kill-the-newsletter.com?

kill-the-news is self-hosted on your own Cloudflare account: your data, your domain, RSS and Atom output, attachments served as enclosures, WebSub push updates — all running on the free tier.

How much does it cost?

It runs on Cloudflare's free tier (Workers + KV + R2) plus the cost of your domain. With Cloudflare Email Routing, no third-party service is required at all.

How do I delete a feed?

From the password-protected admin UI — open the Feeds tab and delete it there. Its entries and attachments are removed along with it.

Does it handle attachments?

Yes — optionally. When an R2 bucket is configured, email attachments are stored there and exposed as RSS/Atom enclosures, downloadable from each entry. It's off by default: if no R2 bucket is bound (or you set ATTACHMENTS_ENABLED = "false"), attachments are simply skipped and everything else works as usual. R2 usage is shown on the status page so you can stay within the 10 GB free tier.

Built on reliable primitives

Minimal dependencies, maximum portability — runs entirely on Cloudflare's global network.

Cloudflare Workers Hono KV Storage R2 Object Storage TypeScript RSS 2.0 Atom postal-mime Zod Vitest

kill-the-news is free and open source. If it saves you time, consider supporting its development.

Sponsor on GitHub