PT Booking Email Investigation — run this on pomelo

Status: Done (2026-07-15). Findings and code changes: popit3/pt-email-findings. Short version: a PT confirmation email exists and the generic parser already handled it correctly (since 2026-06-21/25) — it was just being deliberately excluded from tracking, which this task fixed.

This note is a self-contained task. Read it and carry it out on pomelo.

Background

John has a rolling PT contract (minimum 3 months) with James at David Lloyd Bristol Emersons Green. We need to know whether David Lloyd sends email confirmations for PT sessions, and if so what they look like so we can add a parser to MyDavidLloydSchedule.py.

All David Lloyd emails arrive at john.dl@critchley.biz and are processed by MyDavidLloydSchedule.process_dl_mails(). The raw emails are stored in ~/.email3.mail.gdbm for approximately 2 weeks before deletion. Emails not matched by the class-booking parser are currently silently ignored (not parsed, not added to the calendar) but ARE eventually deleted.

Task 1 — Search the raw email store

Search ~/.email3.mail.gdbm for any emails from David Lloyd that mention James, personal training, or PT. The GDBM stores uidl → {size, mail} where mail is the raw email string.

import gdbm, json, email

results = []
with gdbm.open('/home/john/.email3.mail.gdbm', 'r') as db:
    key = db.firstkey()
    while key:
        try:
            val = json.loads(db[key])
            raw = val.get('mail', '')
            if 'john.dl@critchley.biz' in raw.lower() or 'david lloyd' in raw.lower():
                if any(w in raw.lower() for w in ['james', 'personal train', 'pt session', 'personal trainer']):
                    msg = email.message_from_string(raw)
                    results.append({
                        'uidl': key.decode(),
                        'subject': msg.get('Subject', ''),
                        'from': msg.get('From', ''),
                        'date': msg.get('Date', ''),
                        'snippet': raw[:500]
                    })
        except Exception:
            pass
        key = db.nextkey(key)

print(f'Found {len(results)} matching emails')
for r in results:
    print(f"\n{'='*60}")
    print(f"Subject: {r['subject']}")
    print(f"From:    {r['from']}")
    print(f"Date:    {r['date']}")
    print(f"UIDL:    {r['uidl']}")
    print(f"Snippet: {r['snippet'][:300]}")

If matches are found: save a full copy of the raw email as a fixture at ~/py/popit3/tests/fixtures/pt_booking.eml for use when writing the parser.

Task 2 — Broaden search if Task 1 finds nothing

If no results mention James by name, search more broadly for any DL email that doesn't match the known class-booking pattern — these are the emails currently being silently ignored:

import gdbm, json, email

with gdbm.open('/home/john/.email3.mail.gdbm', 'r') as db:
    key = db.firstkey()
    while key:
        try:
            val = json.loads(db[key])
            raw = val.get('mail', '')
            if 'john.dl@critchley.biz' in raw.lower() or 'david lloyd' in raw.lower():
                msg = email.message_from_string(raw)
                subj = msg.get('Subject', '')
                # Class booking emails typically say 'Booking Confirmation' or 'Booking Cancellation'
                if not any(w in subj for w in ['Booking Confirmation', 'Booking Cancellation', 'Booking Reminder']):
                    print(f"Subject: {subj}")
                    print(f"From:    {msg.get('From', '')}")
                    print(f"Date:    {msg.get('Date', '')}")
                    print()
        except Exception:
            pass
        key = db.nextkey(key)

Task 3 — Report findings to notes

Write a brief summary to popit3/pt-email-findings in the public notes store (use the MCP notes tools) with:

• Whether a PT booking email exists in the GDBM

• Subject line and sender if found

• HTML structure summary (what fields are present: date, time, trainer name, venue, ref)

• Whether it is safe to implement a parser, or whether DL simply does not send PT confirmation emails

Task 4 — If a PT email is found, implement the parser

Add a PT session parser to MyDavidLloydSchedule.py alongside the existing class-booking parser. It should:

• Extract: session date/time, trainer name (James), venue, booking reference

• Add the session to the GDBM calendar and timetable.html alongside class bookings

• Add it to Google Calendar as a separate event (distinct colour/title from classes)

• Add a test fixture and test case in tests/test_dl_email_parsing.py

Context

• popit3 architecture: popit3 and popit3/architecture

• Current todo: popit3/todo — PT bookings are the top urgent item

• David Lloyd routing: john.dl@critchley.bizMyDavidLloydSchedule.process_dl_mails()

• Raw email GDBM: ~/.email3.mail.gdbm (keys are UIDLs, values are JSON with 'mail' field containing raw RFC2822 email)

version 1  ·  created 2026-07-14