Automatically imports bank transactions from Gmail into Actual Budget by parsing email notifications and syncing them via the Actual Budget API.
- Scheduler — runs on a configurable interval, fetches unread emails from Gmail that match your bank notification patterns.
- Parser — extracts transaction type (debit/credit/transfer) and amount from email subjects/bodies using per-bank regex rules.
- Importer — pushes the parsed transactions into Actual Budget via a local API bridge.
- Admin UI — a Django admin interface to manage bank accounts, parsing rules, configuration, and view sync logs.
| Service | Description |
|---|---|
api_server |
Node.js bridge between the Django backend and the Actual Budget server |
backend |
Django app — admin UI, migrations, static files (port 8000) |
scheduler |
Runs fetch-sync on a timed loop; interval is configurable from the admin UI |
- Docker and Docker Compose
- A running Actual Budget server
- A Gmail account with bank notification emails
- Gmail OAuth credentials (see setup below)
git clone https://github.com/rnium/ab_email_sync.git
cd ab_email_syncCopy the env files and fill in your values:
cp backend/.env.example backend/.env
cp api_server/.env.example api_server/.envbackend/.env
| Variable | Description |
|---|---|
SECRET_KEY |
Django secret key (generate a long random string) |
DEBUG |
True for development, False for production |
ALLOWED_HOSTS |
Comma-separated list of allowed hostnames, or * |
ACTUAL_API_SERVER_URL |
URL of the api_server service (default: http://api_server:3000 in Docker) |
EMAIL_MAX_AGE |
How many days back to fetch emails (default: 1) |
EMAIL_MAX_RESULTS |
Max emails to fetch per run (default: 1000) |
GITHUB_SSO_CLIENT_ID |
(optional) GitHub OAuth app client ID — enables "Sign in with GitHub" (see GitHub SSO) |
GITHUB_SSO_CLIENT_SECRET |
(optional) GitHub OAuth app client secret |
GITHUB_SSO_ALLOWABLE_DOMAINS |
(optional) Comma-separated email domains allowed to sign in via GitHub (default: gmail.com) |
api_server/.env
| Variable | Description |
|---|---|
ACTUAL_SERVER_URL |
URL of your Actual Budget server |
PORT |
Port the bridge listens on (default: 3000) |
The SQLite database is bind-mounted from the host so it persists across container rebuilds:
touch backend/db.sqlite3docker compose up -d --buildThe admin UI will be available at http://localhost:8088.
docker compose exec backend python manage.py createsuperuserNavigate to System → Configuration and fill in:
- Actual Budget Password — your Actual Budget server password
- Actual Budget Sync ID — the budget sync ID from Actual Budget
- Gmail Credential JSON — paste the contents of your OAuth credentials JSON file (downloaded from Google Cloud Console)
Then set up Bank Accounts and their Email Parsing Rules to match your bank's notification emails.
Run the OAuth flow once on your local machine (a browser will open):
docker compose exec -it backend python manage.py gmail_auth
# or, if running outside Docker:
python manage.py gmail_authThe token is saved to the database and refreshed automatically from that point on.
By default the admin login page shows the usual username & password form. You can additionally enable a "Sign in with GitHub" button. This is entirely optional — if the credentials below are not set, the GitHub button is automatically hidden and only the username/password form is shown.
- Go to GitHub → Settings → Developer settings → OAuth Apps → New OAuth App (for an organisation, use the org's developer settings instead).
- Fill in:
- Application name — anything, e.g.
AB Email Sync - Homepage URL — where the app is hosted, e.g.
http://localhost:8000 - Authorization callback URL —
<your-host>/github_sso/callback/(e.g.http://localhost:8000/github_sso/callback/)
- Application name — anything, e.g.
- Click Register application, then Generate a new client secret.
- Copy the Client ID and Client secret.
In backend/.env:
GITHUB_SSO_CLIENT_ID=your_client_id
GITHUB_SSO_CLIENT_SECRET=your_client_secret
# Optional: restrict which email domains may sign in (default: gmail.com)
GITHUB_SSO_ALLOWABLE_DOMAINS=gmail.comRestart the backend so the new settings are picked up:
docker compose up -d --build backendThe GitHub button will now appear on the login page.
Auto-creation of users is disabled — signing in with GitHub does not create a new account. The GitHub account's verified email must:
- match the email of an existing Django user (create one via
createsuperuseror the Users admin), and - belong to one of the domains in
GITHUB_SSO_ALLOWABLE_DOMAINS.
If either condition fails, the sign-in is rejected.
The scheduler interval is configurable live from the admin UI under System → Configuration:
| Key | Default | Description |
|---|---|---|
| Daytime start hour | 8 |
Hour when daytime interval begins (0–23) |
| Daytime end hour | 23 |
Hour when daytime interval ends (0–23) |
| Daytime interval | 5 |
Minutes between runs during the day |
| Nighttime interval | 15 |
Minutes between runs at night |
Changes take effect on the next tick — no restart needed.
Run the backend locally:
cd backend
python -m venv venv && source venv/bin/activate
pip install -r requirement.txt
python manage.py migrate
python manage.py seed_configurations
python manage.py createsuperuser
python manage.py runserverA pre-commit hook runs the Django test suite and aborts the commit if any test fails. The hooks live in the tracked .githooks/ directory. Activate them once per clone:
git config core.hooksPath .githookscd backend
python manage.py testMIT — see LICENSE.