2025-04-25 12:35:39 -07:00
2025-04-24 16:30:25 -07:00
2025-04-24 00:33:20 -07:00
2025-04-24 00:33:20 -07:00
2025-04-24 18:18:24 -07:00
2025-04-24 18:18:24 -07:00

Actual IMAP Poll

This project is designed to poll an IMAP server, looking for transaction notification emails which are pushed to an Actual Budget instance.

Docker Usage

To run this project using Docker, you need to configure the following environment variables:

Environment Variables

Variable Name Description Example Value
IMAP_SERVER The hostname or IP address of the IMAP server. imap.example.com
IMAP_PORT The port number for the IMAP server. 143
IMAP_USER The username for authenticating with the IMAP server. user@example.com
IMAP_PASS The password for authenticating with the IMAP server. yourpassword
IMAP_STARTTLS Whether to use TLS for the IMAP connection (true or false). true
IMAP_INTERVAL The interval (in seconds) between polling the IMAP server. 300
ACTUAL_SERVER The URL to the Actual Budget instance to submit transactions to https://demo.actualbudget.org
ACTUAL_PASSWORD The password for the Actual Budget instance password
ACTUAL_SYNC_ID The 'sync ID' UUID of the Actual Budget budget on the server (see Settings / Advanced) 145b1875-8d2c-4eac-aa2c-b3fd937c6a6d
CONFIG_PATH Path to a Python module containing a description of the parsers to execute (see below). /data/config.py

Parser Definition

The parsers to execute and their parameters are defined in a Python source file which should be mounted to the container at the location specified by CONFIG_PATH (e.g. /data/config.py). This file should define a list called PARSERS which holds a list of TransactionParser instances. Since it is Python source, it can also contain custom TransactionParser instances.

Each parser instance will generally require the account UUID to link the transactions to, which can be obtained from the end of the URL while viewing the account in Actual.

Example config.py

from parsers import RogersBankParser, MBNAParser
from uuid import UUID

PARSERS = [
    RogersBankParser(UUID("ae662c3c-3f36-4aee-a558-aa32ff7b75c8")),
    MBNAParser(UUID("82a382e6-ff27-49af-841f-0cbddee9fe28")),
]

Custom Parser Implementation

Parsers must implement the abstract class TransactionParser defined in parsers.py. This class requires two methods:

  1. match(self, msg: Message) -> bool accepts a Message/EmailMessage object and uses it to determine if this parser is responsible for the message and it contains an interesting transaction
  2. extract(self, msg: EmailMessage) -> Transaction accepts an EmailMessage object and extracts a Transaction dataclass object for submission to Actual

Example custom parser

Below is a minimal example of a custom parser for a fictional bank, "Minimal Bank." This parser matches emails from "Minimal Bank" and extracts transaction details. It should appear in the config.py alongside the PARSERS definition.

class MinimalBankParser(TransactionParser):
    def __init__(self, account_id):
        self.account_id = account_id # Actual account UUID to submit the matching transactions to

    def match(self, msg):
        return msg["From"] == "Minimal Bank <alerts@minimalbank.com>" and "Transaction Alert" in msg["Subject"]

    def extract(self, msg):
        body = msg.get_body().get_content()
        amount = ...  # Extract amount from body
        date = ...    # Extract date from body
        payee = ...   # Extract payee from body
        return Transaction(
            account=self.account_id,
            date=date,
            amount=amount,
            payee=payee,
            notes="via Minimal Bank email",
            imported_id=msg["Message-ID"],
        )

Example Docker Command

docker run -d \
    -e IMAP_SERVER=imap.example.com \
    -e IMAP_USER=user@example.com \
    -e IMAP_PASS=yourpassword \
    -e ACTUAL_SERVER=https://demo.actualbudget.org \
    -e ACTUAL_PASSWORD=password \
    -e ACTUAL_SYNC_ID=145b1875-8d2c-4eac-aa2c-b3fd937c6a6d \
    -v /path/to/config.py:/data/config.py \
    actual-imap-poll:latest
Description
Poll an IMAP server for transaction notification emails and import them to Actual Budget
Readme 56 KiB
Languages
Python 77.9%
JavaScript 18.2%
Dockerfile 3.9%