Docs Spam protection
Docs
Spam protection
Spam filtering runs in four layers. The first two are always on, for every plan including Free, and never send your data anywhere. The other two are optional and per-endpoint, and clearly labelled when they're involved.
| Layer | Default | On a hit |
|---|---|---|
| Honeypot | Always on | Silent success response, nothing stored |
| Heuristic scoring | Always on | Held (clear match) or delivered flagged (borderline) |
| Turnstile | Off — opt in per endpoint | turnstile_failed, 403 |
| AI classification | Off — opt in per endpoint | Submission held, reviewable in dashboard |
1. Honeypot — always on, free, first-party
A hidden field (_hp) that only bots fill in. If it arrives non-empty, PostTo responds as if the submission succeeded, but discards
it — nothing stored, nothing emailed. This layer runs entirely inside PostTo; no data ever leaves. See reserved fields for the exact markup.
2. Heuristic scoring — always on, free, first-party
Every submission that gets past the honeypot is scored by a rules-based check before anything else happens. Like the honeypot, this runs entirely inside PostTo — nothing is sent to a third party, and it's on for every plan including Free. It looks at things like:
- An unusually high number of links in the message
- Known spam phrases — PostTo's own curated list, plus your own if you've added any (see below)
- A sender email on a known disposable or spam-associated domain — again PostTo's list plus your own
- The same message submitted to the same endpoint repeatedly in a short window
A clear match is held rather than delivered; a borderline result is delivered but marked flagged so you can glance at it. If
you've enabled AI classification below, borderline results go there for a second opinion instead of being flagged outright. We deliberately
don't publish the exact scoring weights or thresholds — the dashboard shows a category like "matched 2 known spam phrases" rather than which
phrases matched, so a spammer probing your form can't reverse-engineer the list.
Adding your own phrases and domains
Starter and above can layer a custom blocklist on top of PostTo's curated one, per endpoint, from Anti-spam → Custom blocklist in the endpoint's settings:
- Spam phrases — any text you want heuristic scoring to treat as a spam signal when it appears in a submission, in addition to PostTo's own list. Useful for spam specific to your form (a product name being impersonated, a phrase from a bot campaign you're currently seeing).
- Blocklisted domains — sender email domains to flag on top of PostTo's disposable/spam-domain list. Useful for blocking a specific domain you keep seeing abuse from.
Both lists add to the platform baseline rather than replacing it, and feed into the same heuristic scoring above — they don't bypass it or add a separate check.
3. Cloudflare Turnstile — optional, bring your own keys
Turnstile is Cloudflare's invisible or lightweight visual challenge. PostTo only stores the secret key and verifies the visitor's token server-side; you create the widget and its site key yourself in your own Cloudflare dashboard.
- Create a Turnstile widget in Cloudflare and copy its site key and secret key.
- Paste the secret key into the endpoint's Anti-spam → Cloudflare Turnstile settings and enable it.
- Add Cloudflare's widget script and a
cf-turnstilediv to your form, using your site key.
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>
<form method="POST" action="YOUR_ENDPOINT_URL">
<input type="text" name="subject" placeholder="Subject">
<textarea name="message" placeholder="Message"></textarea>
<div class="cf-turnstile" data-sitekey="YOUR_SITE_KEY"></div>
<button type="submit">Send</button>
</form>
The widget submits its result as cf-turnstile-response, which PostTo verifies against Cloudflare and strips before storing the
submission. A failed or missing token returns turnstile_failed (403). If Cloudflare's own verification service is unreachable,
PostTo fails open — a Cloudflare outage doesn't block your legitimate submissions.
4. AI classification — optional, opt-in, only for borderline cases
When enabled on an endpoint, submissions the baseline check can't confidently call clean or spam are sent to an AI classifier for a second opinion. It's off by default, included on Pro and Scale, and available as a $5/month add-on on Starter.
- Only ambiguous submissions are sent. Anything the baseline check already scores clearly doesn't go anywhere near the classifier.
- It's a sub-processor relationship. Enabling it requires acknowledging a one-time consent notice, since submission content is sent to Anthropic's API under a Data Processing Agreement.
- It fails open. If the API errors or times out, PostTo delivers the submission anyway with
spam_scoreleftnulland statusunscored— a classifier outage never blocks your mail.
Nothing is silently dropped
Submissions that fail heuristic or AI checks become status held — stored, visible in your dashboard, and deliverable manually if
they turn out to be legitimate. The honeypot is the only exception, and that's deliberate: it's meant to look identical to success from the
bot's point of view, and it's not a submission a human ever meant to send.
Try it against your own form
Create an endpoint and get a working URL in under a minute — free plan, no credit card.
Start for free