Pulling every PDF out of a Gmail label, one folder per month
A small CLI that downloads PDF attachments from emails with a specific Gmail label, organised into monthly folders, with date filtering and OAuth2 authentication.
Once a year I have to put together my paperwork for the tax return. Bank statements, invoices, salary slips, charity receipts — most of which arrived as PDF attachments in Gmail at some point in the year. The dance has always been the same: search “has:attachment label:Tax 2025”, scroll the list, click each thread, save each PDF, repeat. By February I’m muttering at the screen. gmail-pdf-downloader is the small CLI that ends that.
Output shape matches the consumer
Files are written to monthly folders by default — ./invoices/2025-04/, ./invoices/2025-05/, etc. The accountant wants the paperwork organised that way, so the tool produces it that way rather than something the user has to reorganise after the fact.
OAuth2 with token caching
Setup is the usual Google Cloud OAuth dance — create a project, enable the Gmail API, configure the consent screen, download credentials.json. After the first run, the token sits in the user config directory and is refreshed automatically. --logout wipes it.
The one-time OAuth cost is real, but every subsequent run is silent. For a tool I run once a quarter at most, anything that prompts each run will get abandoned in favour of clicking through the Gmail UI again.
Full project scaffolding for a small tool
The repo has a pyproject.toml, tests, a CI pipeline, and documentation published on GitLab Pages. For a 200-line CLI that sounds heavy, but the cost of putting those four things in place has dropped to almost nothing, and they’re what separate “script that works on my laptop” from “tool I can hand someone”.
I default to the full scaffolding for almost everything now — the marginal cost of doing it right is lower than the marginal cost of explaining the missing pieces later.
Was it worth it?
Tax season is now uv run gmail-pdf-dl -l "Tax 2025" -o ./tax --since 2025-01-01 --until 2025-12-31 and a coffee.
dmorel69/gmail-pdf-downloader— Python, Gmail API