Skip to main content

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.

Metadata

Release files for feed2email 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for feed2email 0.2.0
File Size Uploaded
feed2email-0.2.0.tar.gz 137.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for feed2email 0.2.0
File Interpreter ABI Platform
feed2email-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 171.8 kB

Release files / feed2email-0.2.0.tar.gz

Download URL feed2email-0.2.0.tar.gz
Size 137.7 kB
Tags Source
SHA-256 checksum
How to use checksums
2246e83184cf1a49a4012be8ca95eb8f75a9c759dbc6b240c68d59f13255aed6
BLAKE2b-256 checksum
How to use checksums
1e506e3abf56cee3001fa84a8ef9c5edfb3d66696298cb979ec43d35285dcf47
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 15, 2026.

Transparency log

Release files / feed2email-0.2.0-py3-none-any.whl

Download URL feed2email-0.2.0-py3-none-any.whl
Size 34.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
ea8b959cd2943d1866031f22729f311f165d157ac16b3e385140ca83a76b085e
BLAKE2b-256 checksum
How to use checksums
ae2e05c2b0717d2cfba9ee883c32f798b4e313f95b2eef2cec853d028c8ca73c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 15, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page