Convert email newsletters into a private RSS feed using Cloudflare Workers + ForwardEmail.
This project is self-hosted, uses your own domain, and keeps your data in your own Cloudflare account.
Many newsletters only support email delivery. RSS readers offer a better reading experience, but getting email-only newsletters into RSS usually means relying on shared third-party infrastructure.
Email-to-RSS keeps the same workflow while avoiding shared domains and shared data stores.
- One-click feed creation from an admin dashboard
- Bulk feed/email deletion from the admin dashboard (safe checkbox-based flow)
- Inline double-confirm delete interactions with toast feedback in the admin dashboard
- Resizable + sortable table columns in the admin dashboard (Table view)
- Unique newsletter addresses per feed (for example
apple.mountain.42@yourdomain.com) - ForwardEmail webhook ingestion with source-IP verification
- Optional per-feed sender allowlist (
email@domain.comordomain.com) - RSS generation on demand (
/rss/:feedId) - Cloudflare KV storage for feed config + email metadata/content
- Password-protected admin UI
- Fully self-hosted on your Cloudflare account
- ForwardEmail forwards inbound messages to
https://yourdomain.com/api/inbound. - The Worker validates the request source against ForwardEmail MX IP ranges.
- The Worker parses and stores incoming content in KV.
https://yourdomain.com/rss/:feedIdrenders RSS from stored items./adminprovides feed management and email deletion.
Main routes:
src/routes/inbound.ts: webhook ingestionsrc/routes/rss.ts: RSS renderingsrc/routes/admin.ts: admin UI + feed CRUD
- Node.js 20+
- A Cloudflare account
- A domain managed in Cloudflare DNS
- A ForwardEmail account
- Clone this repository.
- Authenticate Wrangler:
npx wrangler login
- Run setup:
bash setup.sh
setup.sh will:
- install npm dependencies
- verify Cloudflare auth (
wrangler whoami) - create KV namespaces (
EMAIL_STORAGE+ preview) - set the
ADMIN_PASSWORDsecret inproduction - generate
wrangler.tomlfromwrangler-example.toml - stamp
compatibility_dateto the current date
- Configure ForwardEmail DNS records in Cloudflare:
| Type | Name | Content | Notes |
|---|---|---|---|
| MX | @ | mx1.forwardemail.net |
Priority 10, DNS only |
| MX | @ | mx2.forwardemail.net |
Priority 10, DNS only |
| TXT | @ | "forward-email=https://yourdomain.com/api/inbound" |
webhook target |
| TXT | @ | "v=spf1 include:spf.forwardemail.net -all" |
SPF |
-
Deploy:
npm run deploy
-
Open
https://yourdomain.com/adminand sign in.
npm install
npm run dev
npm test
npm run buildwrangler-example.tomlis the template;wrangler.tomlis generated locally.- Keep
compatibility_datefresh when doing runtime upgrades. ADMIN_PASSWORDis a Cloudflare Worker secret, not a plain env var in config.
- Inbound webhook access is IP-restricted to ForwardEmail MX sources.
- Admin auth uses a signed,
HttpOnly,Secure,SameSite=Strictcookie. - Admin responses are
no-storeto avoid cache leakage. - For high-value feeds, set
Allowed sendersso only known sender addresses/domains are accepted. - You should use a strong admin password and rotate periodically.
- Open
/admin. - Switch to Table view.
- Use the search box to filter obvious spam feeds.
- Long titles/URLs are truncated; hover to see the full value. Click to copy.
- Drag the column separators to resize; click headers to sort (double-click a separator to reset width).
- Use Select Results to select the filtered rows, then click Delete Selected.
- Bulk deletes run in small batches so the UI stays responsive. Keep the tab open until it finishes.
- For legitimate feeds that got spam emails, open Emails, filter by subject, then Select Results and Delete Selected.
To refresh dependencies to latest:
npm outdated
npm install
npm test
npm run buildThen update compatibility_date and redeploy.
MIT