Monitor RSS/Atom feeds and deliver new items via email
Project description
feed2email
A command-line tool that monitors RSS/Atom feeds and delivers new items via email. It stores state in a local SQLite database and sends mail over SMTP.
Installation
Requires Python 3.13 or later. Published on PyPI.
uv tool install feed2email
This installs feed2email as a standalone CLI tool managed by uv. You can also use pip:
pip install feed2email
Quick start
Run the setup wizard to configure SMTP and a default recipient:
feed2email init
Add a feed:
feed2email add https://example.com/feed.xml
Fetch new items and send them:
feed2email run
By default, when you add a feed all existing items except the most recent one are marked as read. The next run delivers only the latest item plus anything published after that point.
Commands
feed2email init Interactive setup for SMTP and recipient
feed2email config Get, set, unset, or list configuration values
feed2email add URL Add a feed (fetches and validates immediately)
feed2email edit REF Edit a feed's settings (URL, dedup key, format, etc.)
feed2email remove REF Remove a feed by URL or ID
feed2email list List all configured feeds
feed2email pause REF Pause delivery for a feed
feed2email unpause REF Resume delivery for a feed
feed2email run Fetch feeds and deliver new items
REF is either the numeric feed ID or its URL.
Global options
--db PATH overrides the database location (also settable via the FEED2EMAIL_DB environment variable). The default path is determined by platformdirs.user_data_dir("feed2email").
--verbose / -v enables INFO-level log output.
Adding feeds
feed2email add https://example.com/rss.xml \
--recipient alice@example.com \
--dedup-key link \
--format html \
--item-date
--recipient sets a feed-specific recipient (falls back to default-recipient from config).
--dedup-key chooses which field prevents duplicate delivery: id (default), link, or title.
--format selects email body format: text (default) or html.
--item-date uses the item's publication date as the email Date header.
--mark-read marks all existing items as read instead of keeping the latest unread.
Configuration
Required keys: smtp.host, smtp.port, smtp.from, smtp.encryption, default-recipient.
Optional keys: smtp.user, smtp.password, user-agent, retry.max, retry.backoff, host-delay.
feed2email config smtp.host mail.example.com
feed2email config smtp.port 587
feed2email config smtp.encryption starttls
feed2email config # list all
feed2email config smtp.password --unset # remove a value
Retry
By default, HTTP requests to fetch feeds are not retried.
You can enable automatic retries for transient errors with exponential backoff:
feed2email config retry.max 3 # retry up to 3 times (default: 0, no retry)
feed2email config retry.backoff 0.8 # backoff factor in seconds (default: 0.5)
Check requests documentation for more informations.
Host delay
If you have multiple feeds on the same host, you can set a delay (in seconds) between requests to avoid hammering the server:
feed2email config host-delay 2 # wait 2 seconds between requests to the same host
feed2email config host-delay 0.5 # fractional seconds are supported
feed2email config host-delay 0 # disable (default)
Changing the dedup key
The dedup key cannot be changed in place because switching it would cause previously-delivered items to be re-sent. Instead, remove the feed and add it back with the new key:
feed2email remove https://example.com/feed.xml
feed2email add https://example.com/feed.xml --dedup-key title --mark-read
Use --mark-read to avoid receiving duplicates of items that were already
delivered under the old key.
Dry run
feed2email run --dry-run
Shows what would be sent without delivering mail or updating state.
How it works
On each run, for each active feed it fetches the feed, deduplicates items against previously seen entries, renders an email (plain text or HTML via Jinja2), sends it over SMTP, and records the item as seen.
Exit codes: 0 = all feeds processed, 1 = partial failure (some feeds or items failed), 2 = total failure.
Development
For contributors and developers working on feed2email itself.
git clone https://github.com/timendum/feed2email.git
cd feed2email
uv sync # install all dependencies including dev extras
The project uses uv for dependency management and just as a task runner.
just test # run tests (pytest)
just lint # lint (ruff)
just fmt # format (ruff)
just typecheck # type check (ty)
just check # all of the above
Tests live in tests/ and mirror the source layout. External calls (HTTP, SMTP) are mocked; databases use temporary paths via pytest's tmp_path fixture.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file feed2email-0.2.0.tar.gz.
File metadata
- Download URL: feed2email-0.2.0.tar.gz
- Upload date:
- Size: 137.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2246e83184cf1a49a4012be8ca95eb8f75a9c759dbc6b240c68d59f13255aed6
|
|
| MD5 |
85908594c71876a54c81ee01186a2dc1
|
|
| BLAKE2b-256 |
1e506e3abf56cee3001fa84a8ef9c5edfb3d66696298cb979ec43d35285dcf47
|
Provenance
The following attestation bundles were made for feed2email-0.2.0.tar.gz:
Publisher:
python-publish.yml on timendum/feed2email
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
feed2email-0.2.0.tar.gz -
Subject digest:
2246e83184cf1a49a4012be8ca95eb8f75a9c759dbc6b240c68d59f13255aed6 - Sigstore transparency entry: 1825009438
- Sigstore integration time:
-
Permalink:
timendum/feed2email@9cc05f8e414827c35b0ecfaf318d6fca5c140f02 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/timendum
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@9cc05f8e414827c35b0ecfaf318d6fca5c140f02 -
Trigger Event:
release
-
Statement type:
File details
Details for the file feed2email-0.2.0-py3-none-any.whl.
File metadata
- Download URL: feed2email-0.2.0-py3-none-any.whl
- Upload date:
- Size: 34.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ea8b959cd2943d1866031f22729f311f165d157ac16b3e385140ca83a76b085e
|
|
| MD5 |
41834cac106acdb84a1ef777df51b397
|
|
| BLAKE2b-256 |
ae2e05c2b0717d2cfba9ee883c32f798b4e313f95b2eef2cec853d028c8ca73c
|
Provenance
The following attestation bundles were made for feed2email-0.2.0-py3-none-any.whl:
Publisher:
python-publish.yml on timendum/feed2email
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
feed2email-0.2.0-py3-none-any.whl -
Subject digest:
ea8b959cd2943d1866031f22729f311f165d157ac16b3e385140ca83a76b085e - Sigstore transparency entry: 1825009451
- Sigstore integration time:
-
Permalink:
timendum/feed2email@9cc05f8e414827c35b0ecfaf318d6fca5c140f02 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/timendum
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@9cc05f8e414827c35b0ecfaf318d6fca5c140f02 -
Trigger Event:
release
-
Statement type: