Your code doesn't ship without a linter. Here's the sending-domain setup and the pre-send checks that keep cold email to local businesses from costing you your domain.
You can spot a local business's broken website in about ten seconds: the expired SSL certificate, the contact form that posts to nowhere, the menu that still says 2019. For a freelance developer, that's a warm lead sitting in plain sight.
Writing to them is the easy part. What catches developers out is everything around the email. Google's sender guidelines, in force since 2024, require every sender to authenticate with SPF or DKIM. Anyone sending 5,000 or more messages a day to Gmail addresses needs SPF, DKIM and DMARC, one-click unsubscribe, and a spam complaint rate under 0.3%. Most freelancers never get near 5,000 a day, but the same filters are judging every message they send.
So the risky part of cold email isn't the copy. It's the batch you send from your main domain at 11 p.m. with a merge field that didn't merge. We'd never ship code that way. Why do we ship email that way?
The typical freelancer setup is a spreadsheet, a template, and either a Gmail tab or a mail-merge add-on. It works right up until it doesn't: One domain for everything. Client invoices, support replies and cold outreach share a reputation. Burn it with outreach, and your invoices land in spam too. The template is checked, the output isn't. Hi {{firstname}} looks fine in the editor. The fortieth rendered email, where the scraper found no name, is the one that goes out broken. Memory as a database. Who did you email last month? Who asked you to stop? If the answer lives in your head or a sheet you didn't open, someone gets emailed twice. Provider terms nobody read. Every major email provider restricts cold outreach in its acceptable-use policy, and Google can suspend a whole organisation's account for spam, not just the mailbox that sent it.
The shift is to stop thinking about "sending emails" and start thinking about "shipping a batch". A batch gets built, checked and then released, and a failed check blocks the release.
Send from a separate domain or subdomain, never your main one, and publish its authentication records before the first email:
Swap the SPF include for your provider's: spf.google.com for Google Workspace, spf.protection.outlook.com for Microsoft 365, or whatever your sending service documents. DKIM is a key your provider generates for you to publish.
Run your checks over the emails exactly as they'll be sent. Every check is a rule, and any failure holds the whole batch:
Note the empty-batch line. Without it, every check passes on zero emails and you get SEND having examined nothing. I learned that one the hard way while building a send gate.
The template is checked, the output isn't. Lint the batch you're actually about to send.
Unsubscribes, bounces and opt-in countries aren't judgement calls, so don't give yourself a flag to skip them. The day you'd reach for --force is the day you're in a hurry.
That script is the core of the idea, and it's yours to use. Keeping it alive is the tedious part: the sent log, the suppression list, the per-country rules, and finding the businesses in the first place.
I built Galactic Outreach to be that pipeline in one place. You pick an industry and a city, and it finds matching businesses from their own websites and OpenStreetMap (it doesn't sell a contact database). It writes a personalised email to each one from your template, then runs up to 29 checks over the whole rendered batch. If a blocking check fails, the batch is held and the check is named. Every check is listed in the docs.
It sends through your own provider: Resend, Amazon SES, Mailgun, SendGrid, or your own Microsoft 365 or Google Workspace mailbox. So the reputation you build is yours. Read your provider's policy first, though, because some, Resend included, forbid cold outreach outright.
It isn't for high-volume teams rotating many mailboxes, or for anyone who needs named decision-makers. Instantly or Apollo fit those better.
Nothing magical, which is the point. Before, you'd find the broken merge field when someone replied "Hi {{first_name}}". After, the batch is held on the review screen with the line that failed. Nobody gets the same email twice, because every contact is logged. Unsubscribes and bounces never come back. Leads in opt-in countries are never sent to.
A connected Google Workspace or Microsoft 365 mailbox is capped at 50 emails a day, about 250 in a working week. That's a steady pace for personal outreach to local businesses, and it isn't a blast.
