Custom Outbound Machine
Flask app · outbound campaign ops
A local Flask app that turns a pile of timestamped campaign CSVs into an outbound operating system — a live funnel, and a mailbox reconcile that works out which drafts actually went out.
An existing Python toolchain could build cohorts, enrich provider data and push email drafts to Outlook — but nobody could see what was happening. Campaign state lived implicitly in timestamped filenames scattered across OneDrive, and because advancing a sequence step rewrites the working set, reading the latest file silently reset the sent / replied / booked counts to zero. Sending is manual by mandate, so the tracking sheet couldn't even be trusted to know which of 100+ drafts had actually gone out.
Built a local Flask app — no database, no cloud, no LLM API key, deliberately — that derives campaign state by reading the files on disk, shows a live funnel and a lifecycle stepper, and reconciles the mailbox via Microsoft Graph to work out which drafts were sent, replied to, or bounced. ~2,700 lines of app code with 75 tests, wrapping ~4,850 lines of existing scripts left untouched. Writes are paranoid: every status change is backed up, atomic, and applied only if the row is still in its expected state.
A team of two-to-four now runs campaigns from a shared folder without learning the script chain. State that used to mean opening the right CSV and counting by hand is a dashboard reporting the cumulative truth — pushed 118, sent 112, replied 7, booked 2 — instead of resetting to zero. Every send is still reviewed by a human; the tool serves the operator's judgement rather than replacing it.
Cognassist-Outbound-Machine/ ├── app.py # Flask app — 14 routes + helpers (523) │ │ ── THE APP'S OWN CODE · 2,188 lines ── ├── lib/ │ ├── campaign_state.py # Reader, Campaign/ContactRow, lifecycle (684) │ ├── registry.py # campaigns.json registry + create (180) │ ├── jobs.py # In-memory background jobs + progress (107) │ ├── graph.py # MS Graph auth + Sent Items/Inbox (270) │ ├── reconcile.py # Pure sent/reply/bounce matching (291) │ ├── tracking_writer.py # Safe, backed-up, atomic write-back (131) │ └── engine/ # Capsule cohort build + enrichment (407) │ │ ── INTERFACE ── ├── templates/ # Server-rendered Jinja2, no SPA (677) ├── static/ # Plain CSS + ~77 lines vanilla JS (460) │ │ ── VERIFICATION ── ├── tests/ # 75 tests across 8 modules (1,171) │ │ ── WRAPPED, NOT REWRITTEN ── └── scripts/ # Pre-existing toolchain, reused untouched (4,845)