đź›’ The Problem: Drifting Delivery Windows
Woolworths, one half of Australia’s grocery duopoly alongside Coles, significantly expanded its delivery services during COVID. As a consequence, I signed up for their free delivery subscription, and make orders quite often. But their delivery windows can be extremely wide, some covering 5 hour periods. This makes sense - they need to have broad timing windows to allow for optimising delivery routing. As your delivery gets closer, this usually narrows down to a 1 hour window. But that window can… “drift”, let’s say, when a computer-optimised route meets the real world.
You’re able to track the delivery progress by logging in online. But this is the sort of thing where I might see a one hour window, clear that hour to make sure I’m home, and then only revisit the tracking site at the end of the hour to see that the delivery window shifted back by a lot. So I spent an hour in anticipation that could, if I’d known, been spent doing something else. I don’t want to have to keep checking the delivery progress! I’d sooner have the status update dynamically anywhere I’m tracking it. Which for me is usually a task in TickTick.
Luckily, Woolworths emails you a tracking link in the delivery confirmation email. And this link has a token which lets you view the progress without needing to log in. And Thunderbird lets you keep a local database containing your emails, which Python can read.
đź”— What I Wanted the Script to Do
So I want some code running on my PC to:
- Parse Thunderbird mailbox file,
- Get most recent Woolworths delivery email,
- Get the tracking link in that email with the token to allow any non-authenticated users with that link to view,
- Programmatically visit the delivery tracking website,
- Read the expected delivery window text once the page loads,
- Send that information to Home Assistant via webhook,
- Which can synchronise the delivery time expected to TickTick,
- And intermittently check repeatedly until the delivery is completed.
So there are lots of moving parts! But none of them are too difficult, it’s just a matter of chaining them sequentially. To implement this, I built a Python script that stitches together a handful of libraries, each solving a specific subproblem.
đź§° The Technical Stack
For parsing local emails, I used Python’s built-in email
module to read and decode MIME content directly from Thunderbird’s MBOX-formatted mail storage. I stream the file line by line to avoid loading massive inboxes into memory, and filter candidate messages using SENDER and SUBJECT_KEYWORDS. Once a relevant message is found, I extract the embedded tracking link using a simple regex search on the HTML payload, relying on the consistency of Woolworths’ link formatting and tokenized URLs.
For headless webpage interaction, I used playwright
(via playwright.sync_api
) rather than alternatives like Selenium due to its better modern JS support and faster execution. This lets me render the live tracking page as a real browser would, wait for content to load, and extract the visible delivery window from the text. I also pattern-match for the phrase “your order has been delivered” to detect terminal states.
The delivery window text (e.g. “5:31pm–6:31pm”) is parsed into datetime
objects using strptime
, so I can compute when to start polling for updates. I designed it to sleep until two hours before the delivery window starts, then enter a polling loop at 5-minute intervals, only logging and reporting updates when the ETA changes or when delivery is confirmed.
For external communication, the script sends JSON payloads to Home Assistant via POST to webhook endpoints - one for reporting the current delivery status, another for the tracking URL itself. This decouples the delivery-checking logic from downstream uses like TickTick integration, allowing Home Assistant to act as a central hub.
To avoid concurrent runs, I use the wmi
module on Windows to enumerate running Python processes and inspect their command lines. If another instance is already running the same script, the new one exits early to prevent conflicts.
Finally, I added timestamped logging to a rotating log file, and structured the logic to fail fast and emit clear diagnostic messages when no relevant email is found, the page structure changes, or parsing fails.
For as much as it’s held together with staples and duct tape, it seems to work fine!
The script now runs automatically each day as part of my morning batch script, alongside other routine automations. It boots up, checks the inbox for any new Woolworths delivery confirmations, and - if one is found - kicks off the tracking chain in the background. By the time I’m ready to start the day, I’ve already got the delivery window synced into TickTick, which I always keep visible on my PC and phone home screen.
The GitHub gist is here, but you’ll need to tweak it to work on your machine by adding the appropriate paths.
đź§ Why It Matters (Especially with ADHD)
This entire flow - a stitched-together relay of mailbox parsing, HTML scraping, delivery slot interpretation, webhook pushing, and task sync - is solving a problem that shouldn’t be this hard: “When is my stuff arriving?” It’s a relatively simple human need. But the official infrastructure doesn’t expose the answer in a push-friendly, programmatically accessible way. So instead of a clean API or structured feed, I’m left reverse-engineering scraps: a tokenized email link, a client-rendered progress page, and vaguely formatted time ranges.
Most people wouldn’t see this as a problem worth solving. Intermittently checking a delivery window every hour or two is trivial. But for someone with attention issues these are exactly the kinds of mental interrupts that compound. I’ll tab over to the tracking site “just for a second,” then drift into email, then Slack, then suddenly I’m deep in unrelated context and the task I was working on is long forgotten. Each check is a small task switch with hidden costs. Left unchecked, that pattern can steal whole days. Offloading that mental loop to automation cuts the loop before it starts. I know the system is watching, so I don’t have to.
(This is an example of Attentional Offloading, which I am hoping to write more about.)
I’ve had days where I was away from home, checked TickTick, and immediately saw the ETA slide forward by an hour: no guessing or waiting, just information flowing where it needs to be. It’s the kind of tool that fades into the background.
The system’s job isn’t to be clever: it’s to vanish. And it does!