DEV Community

Cover image for I Built ProMailer to Cold Email Criminal Lawyers. Here's What Happened When I Asked Copilot to Review It.
William
William

Posted on

I Built ProMailer to Cold Email Criminal Lawyers. Here's What Happened When I Asked Copilot to Review It.

Submission for the GitHub Copilot Challenge — William (@nightowl), Minesing Ontario

Why I Built This
I'm building LexSort — a case management tool for Ontario criminal defence lawyers that runs entirely on your own hardware. No cloud. No third party touching client data. Built for solo practitioners who are drowning in admin.
To find co-designers I needed to reach lawyers directly. I looked at outreach tools. Nothing fit what I needed and I wasn't paying SaaS prices for something I could build. So I built ProMailer.
Yesterday the first 20 cold emails went out to criminal lawyers across Ontario. The next 20 are going out right now as I write this.
That's not a demo. That's the tool running live on a real problem.
Live: promailer.ca — justmemedia.ca — lexsort.com

The Problem I Just Solved
ProMailer worked. But every buyer needed Python installed. They needed to know what a terminal was. Small business owners — the people who would have tried would hit that wall and stop.
So I spent this sprint solving it. The goal: native double-click app on Mac, Windows, and Linux. Zero Python required on the buyer's machine.
One unified entry point: app_launcher.py. PyInstaller compiles it into a platform binary. It does three things:

Checks if .env exists next to the executable
If not → Tkinter GUI setup wizard fires. No terminal. No config files. Just a form.
If yes → Flask starts in a background thread, browser opens at localhost:5050

Platform Output What the buyer does on the macOS ProMailer.app ,was Double-click in Finder. For Windows ProMailer.exe Double-click in Explorer. Linux ProMailer binary Double-click or ./ProMailer
One .env. Three platforms. No Python knowledge needed, no terminal commands.

What Happened When I Asked Copilot to Review It
I'm going to be straight about this.
I opened Copilot Chat in my Antigravity IDE, got GitHub authenticated and connected, typed @workspace Review this codebase. What are 3 minor code polishes or error-handling improvements we can add? — and Copilot sat there silent. "No context data." No response.
I've got the screenshots. You can see the query sitting there unanswered.

That's the real developer story. Tools don't always fire when you need them to. You note it, you move on, you ship anyway.
What I can tell you from working with Copilot's inline autocomplete on this codebase: it earns its place on documentation. The _valid_email() helper in lead_finder.py — 15 lines checking regex, length, domain exclusions, TLD allowlists — had no docstring. Type """, pause, and Copilot drafts the whole thing. Not just "validates an email." It explains why each check exists.
In database.py I started:
python# Set write-ahead logging (WAL) to allow
Copilot finished it with the threading reason. One Tab. Accurate. For a solo developer where documentation is always the first casualty, that's worth something.

What Copilot Didn't Do
It didn't design the launcher architecture. It didn't solve the threading problem between Flask and the scraper. It didn't write the PyInstaller spec files.
Those required me to sit with the problem and make decisions. Some of those decisions were wrong the first time.
Copilot is useful for saying clearly what your code is already doing. That's a real thing — especially when you're the only person in the room.

Where This Is Going
The build system is done. ProMailer ships as a double-click app now. And right now it's doing exactly what I built it to do — reaching criminal lawyers across Ontario one inbox at a time, looking for the right co-designers to build LexSort properly.
If it gets one good reply out of these 40 emails, it paid for itself.

William Commu — Just Me Media / LexSort
Minesing, Ontario
@nightowl on DEV
Tags: #githubcopilot #devchallenge #python #buildinpublic

Top comments (0)