Writing · 2026-07-02Tokyo · Incoming Cambridge HSPS

your outreach needs a validator

a hard gate for outreach drafts: single line, product link required, em dashes banned, template clones rejected. it failed 358 of the 414 drafts sitting in my queues.

a subscribe pitch in my linkedin queue burned 17 real people before i noticed the copy was identical in every message. that was vibes-based quality control: skim three drafts, they read fine, send the batch. the drafts you skim are never the ones that hurt you. so i wrote validate_outreach.py, a hard gate every draft passes through before it can send. the gate is binary. a draft that fails one check stays in the queue.

the structural checks came straight from observed failures. single line only, because linkedin truncates a multi-line dm and the recipient receives a naked 'hi jason'. minimum 60 characters, because anything shorter is a naked greeting anyway. the product link has to be present, since a message with no way to see what i built is a dead end. em dashes are a hard ban, the fastest ai tell there is. and the exact subscribe phrasing that burned those 17 people sits in a banned list, checked against a squashed form of the text so 'sub scribe' and 'news-letter' cannot sneak past.

cold openers get stricter rules. the first message to a stranger has to ask about their world, and it cannot demand their time. 'hop on a quick call' fails. a regex catches the time-ask shapes a plain substring list missed, like 'could we set up some time to talk'. the earliest version required a literal question mark in every opener. that rule produced monotone drafts where every message asked a formula question, so it got loosened: the gate now rejects the blast shape, meaning any draft that says nothing about the recipient and asks nothing at all. the ask still has to be there. it just gets to sound human.

the sneakiest failure is the name-swapped template clone. each draft reads fine on its own. so the gate compares every draft in a batch against every other draft using token overlap, and past 0.7 similarity both drafts get flagged and both fail. a human reviewer approves clones all day because no single message looks wrong. the batch view is the only place the pattern is visible.

the receipt: i ran the gate over my frozen queues today. 414 drafts. 56 passed. 358 failed. the breakdown was 266 missing the product link, 259 flagged as template clones, 80 carrying the exact subscribe pitch, 16 multi-line, 6 with em dashes. the old pipeline would have sent all 414. that is 358 small burns to people i actually wanted to talk to, prevented by about 250 lines of python that took an afternoon.

a validator turns taste into checks. every time a draft embarrasses you, the failure becomes one more line in the banned list, and that class of mistake never ships again. reviewers get tired by draft 30. a regex reads draft 414 with the same attention it gave draft 1. what is the one failure your last outreach batch shipped that a check like this would have caught?

More writing