Bollette Auto
A self-hosted system that watches my inbox, automatically downloads household utility bills from provider portals, files them on my home NAS, and extracts their data into a web dashboard — with Telegram notifications.
The problem
Every month, the same chore: an email arrives from the provider, log into the portal, download the PDF, rename it, save it to the right folder. Multiply that by electricity, gas, phone and internet and it becomes a tedious, repetitive task — exactly the kind of thing a computer should be doing for me.
What it does
Bollette Auto (“auto bills”) runs in the background inside a small Docker container and, on its own:
- Checks the inbox over IMAP (Gmail and other mailboxes) at regular intervals.
- Recognises bill emails by their sender.
- Downloads the PDF from the provider’s portal.
- Files it on the NAS in a tidy
year/PROVIDER/structure. - Extracts the data from the PDF into a database so it can be explored.
- Notifies the outcome on Telegram — bill downloaded, or an error.
How it works
At its core is an IMAP polling loop: each mailbox gets its own thread that checks for new mail, routes it to the right provider, and triggers the matching scraper. The downloaded PDF is handed to the archiver, which stores it on the NAS (mounted over CIFS) under the folder for that year and provider.
Two download strategies
- Browser (Playwright) — for portals that require interactive navigation. The
scraper is configuration-driven: the CSS selectors for the login page and the
download are described in a YAML file, so adding a “standard” provider needs no
code. For robustness the download tries several strategies in sequence (URL in
the
onclick, native browser download, opening a new tab, direct link). - Direct API — for portals that expose REST APIs. A dedicated scraper logs in and downloads the PDF without launching a browser: faster and more reliable.
Configuration-driven design
A single YAML file describes mailboxes, providers, selectors and notifications.
Most providers can be added without touching code; only the “hard” portals —
single-page apps with tokens in sessionStorage, unusual APIs — need a small
dedicated scraper in Python.
From PDFs to a dashboard
The bills don’t just sit as PDFs in a folder. Each file is parsed (text extraction with pdfplumber) to pull out the amount, billing period, invoice date, consumption and provider, and the data lands in a SQLite database.
On top of that data runs a web dashboard — a separate FastAPI + Uvicorn service with a static frontend and Chart.js charts:
- Overview — summary cards, monthly spend and consumption charts, a per-provider breakdown and annual spend.
- Bills — a paginated table with provider / year / month filters.
- Supplies — a card per provider with the supply details (POD / customer code).
- Trends — commodity price over time and consumption per provider.
The filters (provider, year, month) are global and persist as you move between tabs.
Security matters
- NAS credentials kept out of the code, in environment variables.
- A dedicated NAS user with read/write access to the bills folder only (principle of least privilege).
- An App Password for Gmail instead of the account password.
- No secrets in version control: everything sensitive stays out of the repository.
Stack
Python · Playwright · IMAP · Docker · Synology NAS (CIFS) · Telegram Bot API
What I learned
- Portals change their HTML often: keeping selectors in configuration rather than in code turns maintenance into a matter of seconds.
- Splitting “generic YAML-driven scraper” from “dedicated scraper” keeps the system simple for the common case and flexible for the hard one.
- Known limitation: portals with two-factor authentication aren’t handled.