Start on the receiving end. A playbook on defending web forms, published on 13 August 2026, describes what its author found when reviewing batches of contact form submissions:
somewhere between a fifth and two-fifths of submissions were junk — random-string bot fills, link-building outreach, and budget-inflation pitches.
Link building outreach, listed between random bot fills and budget pitches. That is the category one reviewer’s batches put it in, before anyone read it. The defences the same playbook recommends, in order, are a honeypot field, rate limits, and a CAPTCHA last, because:
CAPTCHA sits last in the order for a UX reason — it is the only layer that taxes every legitimate visitor.
Akismet, the filter that by its own count runs on more than 100 million sites, says it has removed over 500 billion pieces of spam at 99.99% accuracy. Those are the vendor’s own figures, and the vendor does not publish what it compares a submission against.
So a person doing outreach through contact forms, for guest posts, partnerships, a listing in a directory, a job application, loses in one of the two ways this article is about.
The two ways to lose
Look like a bot. The automated end of the market advertises exactly what the defences are built for: paste a few hundred domains, let a model map the fields, solve the CAPTCHA, submit, pay per success. A rate limit exists for the submission rate, a challenge for the CAPTCHA solver, a honeypot for the model that fills every field it maps, and every step in that list is one where the message goes out without a human having read the page it goes to.
Look like a copy. The manual end has its own failure. Paste one message into 200 forms and 200 sites receive the same text. A site owner who has seen it once on a colleague’s blog does not need a filter, and a filter that learns across sites, if that is what it does, has 199 chances to learn this one.
The tools built for manual outreach converged on one interaction for this: a button that copies the rendered message and opens the contact form, after which the person presses Send and marks the row as done. That is the right shape. What it leaves to the person is the two things above: writing 200 messages that are not one message, and pasting each into the right fields without mistakes.
One template, a list, a person on Send
That is the gap the Spintax Manual Outreach Helper was written for, and shipping it is the occasion for this article. It is our own extension, free, GPL, and since 28 August 2026 version 0.2.1 is live on the Chrome Web Store, Edge Add-ons and Firefox Add-ons.
The flow is the one the manual tools already use, with the two gaps filled:
- Import the list. CSV, XLSX or a paste from a spreadsheet. Columns become variables
(
%name%,%site%,%topic%), roles are detected from the values, and duplicates are merged by the target’s key: the hostname for a URL, the address for an email, the handle for a profile. - Write one template in spintax, or let the built-in prompt draft it in your own chat. The extension sends nothing to any model; it opens the prompt in a tab or copies it.
- Review before the first message: variables highlighted, warnings for an empty variable, a leaked brace, a field longer than the form allows.
- Open the side panel on the target page. The helper recognises the contact form, fills the fields it understands from that row, reports what went where and what it could not find, and waits. You read the message, press Send on the page yourself, mark the row. The next one is already there.
- Follow-ups are steps. A row comes back into the same queue on its due date with the step two template. Outcomes, sent, deferred, no form, captcha, replied, declined, live in a local journal you can export.
The boundary is written into the design rather than the settings. From the README:
It never submits a form, never solves a captcha, never scrapes a page, never adds “human-like” delays. That boundary is a design rule, not a setting.
The manifest matches the sentence, and so do the permission justifications filed with the stores: no host permissions and no content scripts at install. Filling a form asks for that one origin, from the Fill button, at the moment you press it, and the injected script has no code path that calls submit. By the same documents there is no server, no account, no analytics, and no network request unless you switch on the one optional news feed.
Measured on its own template
The extension ships a demo campaign, guest posts to five targets, four demo pages and one email address, with a template of about 45 words, so the whole flow can be tried without touching a real site. The template has 14 places with two options each, 16,384 wordings on paper. The rendering rule is the part worth checking, because it is what separates a queue of 200 messages from one message pasted 200 times: the seed for every row is the row’s key and the step number, so the same site always gets the same wording and a follow-up gets a different one.
Two hundred synthetic rows through the engine the extension bundles, @spintax/core:
| Question | Measured |
|---|---|
| Distinct wordings across 200 rows, values blanked | 197 of 200, against 199 predicted by the birthday arithmetic |
| The same row rendered twice | identical, all 200 |
| Step two on the same row differs from step one | 199 of 200 |
| Rows with an empty topic | 25 of 25 rendered with a visible gap, the kind of hole the review screen is built to flag |
| Share of each message identical across 95% of rows | 7.1%: the ask, “accept a guest post for” |
The first row is the whole argument in one number. A template of about 45 words, written once, gives 200 blogs 197 different messages, and blog number 140 gets the same one every time you open its row. The last row is the honest complement, and it is the same finding as in the cold email measurement: what stays constant is the ask, which is the part a reader should recognise.
The file is measure.mjs; it needs Node and the engine from npm:
npm install @spintax/core@0.6.1
node measure.mjs
Where the extension stops
It recognises fields by autocomplete attributes, input types and labels in seven languages, and remembers the mapping per site as a recipe. A field it cannot place is yours to point at once; a rich editor, Gmail or LinkedIn, gets the text through the clipboard. A CAPTCHA is an outcome in the journal, not a problem it solves. It does not read the target page for you, does not find the contact page, and does not tell you whether the site is worth writing to.
The store side of this deserves a paragraph, because the theme of the article happened to the article’s subject. On 26 August 2026 the Chrome Web Store pulled the listing: the description named the form builders the helper recognises, and the store read the list as keyword stuffing. The corrected text was auto-rejected the same day; an appeal was granted on 27 August with the same package. A helper built so that a person, not a script, sends each message spent a day filed as the script.
What spintax has to do with it
Nothing in the flow above needs the template syntax to be clever. The demo template uses the plainest construct there is, two options in braces, fourteen times, and that is enough for 200 rows. What the syntax buys is that the message can be a template at all: variables from the row, a follow-up that is a second step rather than a second campaign, and a wording that is reproducible from the row’s key when someone asks what you sent.
The craft, which options to fork and which to leave alone, is on spintax.net: the cold email page for where variation goes and the authoring guides for how to write it. The extension is the hand at the end of that pipeline, the one that keeps a person on Send. Whether that keeps a message out of anyone’s spam folder is not something this article measured.