Killing My 13-Year-Old Contact Form

Killing My 13-Year-Old Contact Form

Tutorials contact-forms email-deliverability personal-blog self-hosting spf-dkim

So I finally did something I've been putting off since approximately forever: I ripped out the contact form on this blog and replaced it with something that isn't a single PHP file from 2011.

I want to be honest about how bad it was. The file was literally named contact.php, it lived in the same directory since I first put this blog on shared hosting, and it called PHP's built-in mail() function with zero authentication, zero SPF alignment, nothing. For years that was fine because nobody cared. Then somewhere around 2023-2024 the big mail providers (you know which ones) started actually enforcing SPF/DKIM/DMARC and bulk sender rules, and my little mail() calls started landing in spam folders roughly 100% of the time. I only noticed because a reader emailed me on Mastodon asking why I never responded to something they'd sent through the form four months earlier. Four months! I never saw it. It just quietly vanished into whatever Gmail does with unauthenticated mail now.

That's the annoying thing about running something continuously for almost fifteen years, stuff just keeps working right up until it silently doesn't, and you have no idea because there's no error, no bounce, nothing. The form said "Message sent!" every single time. It just wasn't landing anywhere I could see it.

What I actually did

I didn't want to run my own mail server. I did that once, around 2015, for about eight months, and I do not recommend it unless you enjoy checking blacklist databases before your morning coffee. Instead I wired the form up to a transactional email API and had it send through proper authenticated SMTP with the right DNS records in place. I ended up using the one baked into Tricknowtech since I already had the domain there anyway, so adding an email sending API key was maybe a ten-minute job instead of a whole new account somewhere else.

The actual steps, if you're in the same boat with some ancient form:

  1. Rip out the mail() call entirely. Don't try to patch it, just delete it.
  2. Get an API key from whatever service you're using and stick it in an environment variable, not hardcoded in the PHP file like some kind of animal (yes, the old one had my email address hardcoded right there in plaintext, in a public-facing repo I'd forgotten was public).
  3. Add the DNS records, an SPF TXT record, a DKIM CNAME or two, and a DMARC policy. This is the part people skip and it's the part that actually matters.
  4. Test with curl directly against the API before you even touch the form's JS. Isolate the variables.
  5. Only then wire the form's POST handler to call the API and check the response code instead of just assuming success.

Whole thing took me about ninety minutes on a Sunday afternoon, most of which was me second-guessing the DNS TTL and refreshing dig output every four minutes like that was going to speed anything up.

The tangent nobody asked for

While I was in there I also found a comment in the old file, in my own handwriting basically, that said // TODO: add spam filtering, ppl keep submitting viagra ads. Dated November 2011. Thirteen years. I never did add spam filtering. I just let it accumulate. When I finally exported the old submissions table before deleting it there were 6,214 rows in it, and a rough skim suggested maybe 40 of them were real humans. The rest was over a decade of pharmaceutical spam, SEO backlink pitches, and at least three separate people trying to sell me "AI content generation services" in 2023 which, given what I do for a living now, is a little bit funny in retrospect.

Anyway. Form works now. If you've sent me something through it in the last two years and never heard back, that's why, and I'm sorry, and also please just email me directly next time because clearly I can't be trusted with my own infrastructure.

The bigger lesson, if there is one, isn't really about contact forms specifically. It's that "it still runs" and "it still works" are two completely different claims, and the gap between them can sit there quietly for years on a blog nobody's actively monitoring. I'd bet there's at least one other thing on this site right now doing the exact same thing. I just haven't found it yet.