{"id":21686843,"url":"https://github.com/jgosmann/doveseed","last_synced_at":"2026-05-11T03:44:58.149Z","repository":{"id":57423787,"uuid":"223602896","full_name":"jgosmann/doveseed","owner":"jgosmann","description":"Doveseed is a backend service for email subscriptions to RSS feeds.","archived":false,"fork":false,"pushed_at":"2024-04-12T04:46:05.000Z","size":622,"stargazers_count":1,"open_issues_count":2,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-04-14T10:43:43.329Z","etag":null,"topics":["email-sender","rss","subscription"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jgosmann.png","metadata":{"files":{"readme":"README.rst","changelog":"CHANGELOG.rst","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2019-11-23T14:35:13.000Z","updated_at":"2024-04-18T17:33:41.022Z","dependencies_parsed_at":"2023-11-23T19:53:37.881Z","dependency_job_id":"f9211346-6ef6-47d4-ad09-96248f282d95","html_url":"https://github.com/jgosmann/doveseed","commit_stats":{"total_commits":98,"total_committers":2,"mean_commits":49.0,"dds":"0.010204081632653073","last_synced_commit":"27d6dc83d59a529203121ecd86f326ae6367a9be"},"previous_names":[],"tags_count":25,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jgosmann%2Fdoveseed","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jgosmann%2Fdoveseed/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jgosmann%2Fdoveseed/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jgosmann%2Fdoveseed/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jgosmann","download_url":"https://codeload.github.com/jgosmann/doveseed/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244609459,"owners_count":20480782,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["email-sender","rss","subscription"],"created_at":"2024-11-25T16:33:26.459Z","updated_at":"2026-05-11T03:44:58.120Z","avatar_url":"https://github.com/jgosmann.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":".. image:: https://github.com/jgosmann/doveseed/actions/workflows/ci.yml/badge.svg\n  :target: https://github.com/jgosmann/doveseed/actions/workflows/ci.yml\n  :alt: CI and release pipeline\n.. image:: https://codecov.io/gh/jgosmann/doveseed/branch/main/graph/badge.svg\n  :target: https://codecov.io/gh/jgosmann/doveseed\n  :alt: Codecov coverage\n.. image:: https://img.shields.io/pypi/v/doveseed\n  :target: https://pypi.org/project/doveseed/\n  :alt: PyPI\n.. image:: https://img.shields.io/pypi/pyversions/doveseed\n  :target: https://pypi.org/project/doveseed/\n  :alt: PyPI - Python Version\n.. image:: https://img.shields.io/pypi/l/doveseed\n  :target: https://pypi.org/project/doveseed/\n  :alt: PyPI - License\n\n.. image:: https://github.com/jgosmann/doveseed/blob/main/doveseed-logo.png\n  :alt: Doveseed logo\n  :width: 145\n\n\nDoveseed\n========\n\nDoveseed is a backend service for email subscriptions to RSS feeds.\n\n\nSetup\n-----\n\nConfiguration\n^^^^^^^^^^^^^\n\nDoveseed requires a configuration file in JSON format. Take a look at\n``config.sample.json``. The format is as follows:\n\n* ``db``: JSON file in which Doveseed persists its data.\n* ``rss``: URL to the RSS feed for which new notifications are to be send.\n* ``smtp``\n\n  * ``host``: SMTP host used to send notification emails.\n  * ``port``: SMTP port used to send notification emails (defaul: ``0`` = auto-select).\n  * ``user``: SMTP logon user name.\n  * ``password``: SMTP logon password.\n  * ``ssl_mode``: Activate/deactivate SSL/TLS, valid values ``\"no-ssl\"``, ``\"start-tls\"``, ``\"tls\"`` (default ``\"start-tls\"``).\n  * ``check_hostname``: Whether to verify the hostname when using TLS (default ``true``).\n\n* ``template_vars``: Defines template variables to replace in the email templates.\n\n  * ``display_name``: Name for the website to use in emails.\n  * ``host``: Hostname of the website.\n  * ``sender``: Email address that is sending the notifications.\n  * ``confirm_url_format``: Template for the URL that is used for confirmation\n    links. The following values will be replaced in it:\n\n    * ``{host}`` with the specified host,\n    * ``{email}`` with the email address to confirm,\n    * ``{token}`` with the confirmation token,\n    * ``{{`` and ``}}`` with ``{`` and ``}``.\n\n* ``email_templates``: Path to the templates for the emails.\n* ``confirm_timeout_minutes``: Timeout in minutes during which a subscription needs to be confirmed.\n\n**Ensure that the configuration files have appropriate permissions, i.e. only\nreadable by you and Doveseed.**\n\nBy default the configuration filename is assumed to be ``config.json``.\n\n\nEmail templates\n^^^^^^^^^^^^^^^\n\nTemplates for the emails sent out are written in\n`Jinja \u003chttps://jinja.palletsprojects.com/en/2.11.x/\u003e`_.\nLook in ``templates/example`` for example email templates.\nThere is a template for each type of email being sent:\n\n* ``new-post.*``: for notifications about new posts,\n* ``subscribe.*``: for requesting confirmation to a new subscription,\n* and ``unsubscribe.*``: for requesting confirmation to a cancellation of a subscription.\n\nEach of these templates consists out of three files:\n\n* ``*.subject.txt``: for the subject line of the email,\n* ``*.txt``: for the plain text version of the email,\n* and ``*.html``: for the HTML version of the email.\n\n\n\nREST service\n^^^^^^^^^^^^\n\nThe REST service runs as a Python `ASGI app\n\u003chttps://asgi.readthedocs.io/en/latest/\u003e`_. See the FastAPI documentation for\n`deployment options \u003chttps://fastapi.tiangolo.com/deployment/\u003e`_.\n\n\n\nCORS\n~~~~\n\nTo set appropriate CORS headers use the `FastAPI CORSMiddleware\n\u003chttps://fastapi.tiangolo.com/tutorial/cors/\u003e`_. Activate it by adding the\nfollowing lines to the file where you instantiate the app::\n\n    from doveseed.app import app\n    from fastapi.middleware.cors import CORSMiddleware\n\n    app.add_middleware(\n        CORSMiddleware,\n        allow_origins=[\"http://example.com\"],\n        allow_methods=[\"GET\", \"POST\"],\n        allow_headers=[\"Authorization\"],\n    )\n\n\nReCaptcha\n~~~~~~~~~\n\nYou activate `ReCaptcha (v2) \u003chttps://www.google.com/recaptcha/\u003e`_ verification of\nrequests with Doveseed.\n\nFirst, you need to install the required optional dependencies::\n\n    pip install 'doveseed[recaptcha]'\n\nThen, add the follwing lines to the file where you instantiate the app::\n\n    from doveseed.app import app\n    from doveseed.recaptcha import ReCaptchaMiddleware\n\n    app.add_middleware = ReCaptchaMiddleware('^/(un)?subscribe/.*', 'recaptcha.json')\n\nAlso, create the ``recaptcha.json`` with the required ReCaptcha configuration:\n\n* ``hostnames``: List of hostnames to accept ReCaptchas from.\n* ``secret``: The shared key between your site and reCAPTCHA.\n\n\n**Ensure that the configuration files have appropriate permissions, i.e. only\nreadable by you and Doveseed.**\n\n\nDatabase cleanup\n^^^^^^^^^^^^^^^^\n\nExpired pending subscription can be cleaned from the database with::\n\n    python -m doveseed.cli clean \u003cpath to config file\u003e\n\nIdeally, this command is run once per day as a cron job.\n\n\nChecking for new posts\n^^^^^^^^^^^^^^^^^^^^^^\n\nTo check for new post and send notification emails run::\n\n    python -m doveseed.cli notify \u003cpath to config file\u003e\n\nThis can either run in a regular interval as a cron job or it can be triggered\nin some way after new posts have been published.\n\n**Run this command once to initialize the database before going live because\ninitially all items in the RSS feed will be considered to be old.** (This\nprevents sending a notification email for all already existing items in the\nfeed.)\n\n\nREST interface\n--------------\n\nHealth\n^^^^^^\n\nTo check the service health:\n\n    GET /health\n\nReturns a 204 (no content) status if the service is up and running.\n\nSubscribe\n^^^^^^^^^\n\nTo subscribe with an email address::\n\n    POST /subscribe/\u003curl encoded email\u003e\n    Content-Type: application/json\n\n    { captcha: \"ReCaptcha returned from Google API\" }\n\nThis will return a ``201 NO CONTENT`` and send out the email requesting\nconfirmation.\n\nUnsubscribe\n^^^^^^^^^^^\n\nTo unsubscribe an email address::\n\n    POST /unsubscribe/\u003curl encoded email\u003e\n    Content-Type: application/json\n\n    { captcha: \"ReCaptcha returned from Google API\" }\n\nThis will return a ``201 NO CONTENT`` and send out the email requesting\nconfirmation if the email is subscribed.\n\nConfirm\n^^^^^^^\n\nTo confirm a request to subscribe or unsubscribe::\n\n    POST /confirm/\u003curl encoded email\u003e\n    Content-Type: application/json\n    Authorization: Bearer \u003ctoken from confirmation reuest email\u003e\n\nThis will return a ``201 NO CONTENT`` on success,\nand ``401 UNAUTHORIZED`` if the token or email is invalid.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjgosmann%2Fdoveseed","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjgosmann%2Fdoveseed","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjgosmann%2Fdoveseed/lists"}