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:
match(self, msg: Message) -> bool
accepts aMessage/EmailMessage
object and uses it to determine if this parser is responsible for the message and it contains an interesting transactionextract(self, msg: EmailMessage) -> Transaction
accepts anEmailMessage
object and extracts aTransaction
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