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. You can also add a sender domain to the second list in one click while reporting a submission, without opening settings.
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.
Auto-replies are held back from suspicious submissions
If you have an autoresponder enabled, it goes out for ordinary submissions only. When a submission is scored as suspicious, the notification still reaches your inbox — nothing is withheld from you — but the automatic reply to the sender is skipped.
The reason is that an auto-reply is a confirmation. It tells whoever sent the message that the address is real, monitored, and answers by itself, which is precisely what an address harvester submits a form to find out. Withholding it costs you nothing on the rare occasion a genuine sender is scored this way — you still have their message, and you can reply yourself — and it keeps your inbox off a list on every other occasion.
This applies whether the verdict came from the always-on layers or from AI classification, and it needs no configuration.
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.
Reporting what we got wrong
No filter is right every time. Every submission carries a report action — on the submission's own page, in your Submissions list, and in an endpoint's Submissions tab — in both directions:
- Report as spam — spam that reached your inbox. Available on any submission.
- Not spam — legitimate mail we held or flagged. Available on submissions we judged suspicious.
Reports go to us, not just to your endpoint: they're what PostTo's curated phrase and domain lists are built from, and what tells us a threshold is set too tight. A report on your form improves filtering for every account, which is also why we'd rather you sent one than quietly deleted the message.
Reporting never changes what already happened. A delivered submission stays delivered and stays in your dashboard — the report is a note about our judgement, not a retraction of your mail. The one exception is opt-in: when you mark a held submission as not spam, the dialog offers to deliver it to your destination in the same click.
On Starter and above, the spam report also offers to add the sender's domain to that endpoint's blocked sender domains. Use it for a domain that exists to send you this — we'll warn you before blocking a shared mailbox provider like Gmail or Outlook, since that holds mail from every sender on it, not just the one you reported.
Reporting the same submission again replaces your earlier verdict, so a change of mind is just another click.
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