Imports General Ledger Statement CSV exports from PowerOffice Go into a local SQLite database, builds an Excel spreadsheet from the stored transactions, and emails it to a recipient list via Gmail. Intended to run monthly as a scheduled job.
- Export a General Ledger Statement from PowerOffice Go as a CSV file.
- Import the CSV into a local SQLite database; reversed and cancelled entries are automatically excluded so only settled transactions are stored.
- Query the database for the previous calendar month's transactions and write them to an
.xlsxspreadsheet. - Look up recipients from a Google Contacts label (
JustMe) whenMAILER_ENVIRONMENT=Production; otherwise fall back to a hardcoded development address. - Send the spreadsheet as an email attachment via Gmail.
- Python >= 3.10
- Poetry for dependency management
| Variable | Required | Description |
|---|---|---|
GMAIL_SENDER |
Yes | Gmail address used as the sender |
GMAIL_APP_PASSWORD |
Yes | Gmail App Password for SMTP |
GOOGLE_ACCESS_TOKEN |
Production only | Google People API access token (contacts.readonly scope) |
MAILER_ENVIRONMENT |
No | Set to Production to use the Google Contacts recipient list |
DB_PATH |
No | Path to the SQLite database file (default: journal.db) |
# Install dependencies
poetry install
# Run tests
poetry run pytest
# Lint and format
poetry run ruff check .
poetry run ruff format .
# Security scan (source only, not tests)
poetry run bandit -r journal_mailerExport a General Ledger Statement from PowerOffice Go (semicolon-delimited, UTF-8). Then import it:
poetry run python -m journal_mailer import --csv "General Ledger - Statement 2026.csv"Reversed entries (text contains "(Reversed)" or starts with "Reversal of voucher") are silently dropped. Re-importing the same file is safe (idempotent).
export [email protected]
export GMAIL_APP_PASSWORD=...
# Development run (sends to the hardcoded dev address)
poetry run python -m journal_mailer send
# Production run (sends to the JustMe Google Contacts group)
export MAILER_ENVIRONMENT=Production
export GOOGLE_ACCESS_TOKEN=...
poetry run python -m journal_mailer sendBuild the image:
docker build -t journal-mailer .Run it, passing credentials as environment variables:
docker run --rm \
-e [email protected] \
-e GMAIL_APP_PASSWORD=... \
-e MAILER_ENVIRONMENT=Production \
-e GOOGLE_ACCESS_TOKEN=... \
-v /path/to/csvs:/data \
journal-mailer import --csv /data/ledger.csv
docker run --rm \
-e [email protected] \
-e GMAIL_APP_PASSWORD=... \
journal-mailer sendThe GitLab CI pipeline (.gitlab-ci.yml) builds and pushes the Docker image to the GitLab container registry on every push to the default branch.
registry.gitlab.com/<namespace>/journal-mailer:latest
registry.gitlab.com/<namespace>/journal-mailer:<commit-sha>
journal_mailer/
__init__.py # Norwegian month names
__main__.py # Entry point: import CSV or send report
csv_importer.py # CSV parsing, reversal filtering, DB upsert
db.py # SQLAlchemy ORM model (LedgerEntry) and engine helpers
contacts.py # Google People API — resolves contact label to email list
models.py # Email and Attachment dataclasses
sender.py # Gmail delivery
report.py # Builds the .xlsx workbook from ledger entries
time.py # Date utilities — previous_month() for report period