The concept is to give the user a custom email address, like “mark-ankcorn-123@dktvue.com” and have them add it to their information on the Pacer system. Every time a document is filed with the federal court, their server generates an outgoing email called a Notice of Electronic Filing which contains a link to the PDF(s) filed by one of the lawyers in the case. Sometimes judges or clerks will post notices without a PDF, like “hearing set for Tuesday is moved to Thursday at 9 am.”
My application has a module written in TypeScript that parses these incoming email, extracts relevant data like the court, case number, document number, link to download the document if any, filer, etc. and writes that information to a database. The next step is to have a separate module take the document link and go get the PDF, give it a name that associates it with the lawsuit, and stick it in a pool of documents. The web app aka “front end code” will have a nice, efficient web page with a table showing all of those documents in order and a little icon so the user can see the actual filing, or download it for local use.
Sounds simple right? Well, not really.
Writing this code to parse the email is really complicated, mostly because there are a bunch of different variations by how different clerks set up their systems, what kind of things get filed as PDFs and which are text-only entries, how various filings are described, and on and on. But I got that sorted out and it seems to play nice with the examples I throw at it.
I created a Worker on Cloudflare and thought I was all set. Nope. The documentation for the Email Workers assumes you want to just have an email for your website, like dave@fubar-widgets.net and send that to your Gmail account. As a way of putting your best foot forward to customers. I get it. Great.
But I want a lot more functionality. I want to direct those incoming emails to my Worker to parse them out, reject emails that aren’t addressed to a valid user, and reject anything that doesn’t come from uscourts.gov to avoid spam.
Making the Worker wasn’t hard. Having Cloudflare recognize that Worker and see it as a valid target for the incoming email Route, well that’s a different kettle of fish.
I originally tried just copying my code over, since Cloudflare provides a nifty little code editor on the website if you click through some of the settings. But it doesn’t like TypeScript and I didn’t want to just copy it to Claude or Gemini and have them translate it, though after several days of going around and around, that was awfully tempting.
Eventually I figured out that the best way to create and deploy is using the Wrangler command line tool, installed via npm install -g wrangler@latest
. Pretty much anything else, including Homebrew, is deprecated or doesn’t include dependencies.
The crucial part is the wrangler.toml
file to specify that you want to use it for email. After several different tries, what worked seemed to be this:
It continually gives me this warning, but it works:
I’m sure it’s not the way the Cloudflare dev team wants this to be described, but I simply cannot find anything in the documentation or in the Discord channel for this to give me anything else. And I only got this after a half-dozen error messages when trying to deploy differently and feeding those errors into Claude 3.6 and begging for help. This makes it visible when setting up an email route, which apparently still needs to be done online. I cannot figure out how to do it on the command line with Wrangler, still.
My code sends the parsed information to a database, so I had to write the schema for that and deploy it, then take the database identifier and write it into the wrangler.toml because it will refuse to deploy the Worker without that off-ramp.
Oh and one more thing — the name for the incoming email address that you need to set up the route is “catch-all” because it doesn’t take an asterisk like every other normal boolean computer since Univac. Again undocumented, but solved by Claude.
I threw a bunch of fake emails at it using curl and iterated on the index.ts code for the Worker until it got it right. Ended up with about 200 lines of TypeScript, well within the limits of the system.
Next step is to give this test email to the courts and wait for a few NEFs to pile up and see if it actually works with live filings. I get a couple per day on various cases, so we’ll see.
One thing I’m really curious about is how long this is going to take to parse an email. The paid plan with Cloudflare is $5 per month (yes, five bucks) and comes with 15 minutes of compute time per request, 10 million requests per month, and 30 million milliseconds of compute per month. Which kind of sounds like a lot. Hoping it won’t be more than 10-20 ms to process an incoming email and write it to the database, but we’ll see. If I go over, it’s $0.02 per million CPU milliseconds.