Skip to content

Spam protection

letterpost screens every submission on every plan. You can add three more layers in the form's settings under Security. They work together; use as many as your form needs.

Honeypot

A honeypot is a hidden field that people never see, so they leave it empty. Bots fill in every field they find. A submission with a filled-in honeypot is dropped: it is not stored, not mailed and not counted, but the bot gets the same answer as a person, so it doesn't learn that it was caught.

  1. Choose a field name in the settings, for example _honeypot. The name must start with _, so the field is never stored with the submission.
  2. Add the field to your form, hidden from people:
<input type="text" name="_honeypot" style="display:none" tabindex="-1" autocomplete="off">

Warning

Once a honeypot field is set, every submission must contain it. A form that doesn't send the field is rejected with the error code invalid, so you notice a forgotten field instead of losing submissions.

The name must start with _, may contain letters, digits, - and _, and is at most 50 characters long. It can't be one of the names letterpost uses itself, such as _subject or _redirect.

Allowed websites

List the websites that may send submissions to the form, one per line, for example https://example.org. Submissions from anywhere else are rejected with the error code origin_not_allowed.

letterpost checks the Origin header the browser sends, or the Referer when there is no Origin. Leave the list empty to accept submissions from every website.

Captcha

A captcha stops bots before a submission is stored. letterpost supports three providers. After you choose one in the settings, the form's page in the dashboard shows the complete snippet for your form, ready to copy.

ALTCHA

No account needed. letterpost creates and checks the puzzle on its own servers; the visitor's browser solves it. No data goes to a third party.

<script async defer src="https://cdn.jsdelivr.net/gh/altcha-org/altcha@3.6.0/dist/main/altcha.min.js" type="module"></script>
<form action="https://api.letterpost.eu/f/k3v9q2" method="POST">
  <label>Email <input type="email" name="email" required></label>
  <label>Message <textarea name="message" required></textarea></label>
  <altcha-widget challenge="https://api.letterpost.eu/f/k3v9q2/altcha"></altcha-widget>
  <button type="submit">Send</button>
</form>

Each solved puzzle is accepted once and expires after 10 minutes. If a visitor leaves the page open longer, the widget fetches a new puzzle.

Cloudflare Turnstile

Free and usually invisible. Create a widget in your Cloudflare account and enter its site key and secret key in the settings.

<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>
<form action="https://api.letterpost.eu/f/k3v9q2" method="POST">
  <label>Email <input type="email" name="email" required></label>
  <label>Message <textarea name="message" required></textarea></label>
  <div class="cf-turnstile" data-sitekey="YOUR_SITE_KEY"></div>
  <button type="submit">Send</button>
</form>

Friendly Captcha

Proof of work, no cookies, made in the EU. Create an application in your Friendly Captcha account and enter its site key and API key in the settings. Tick Verify in the EU to have the check run on Friendly Captcha's EU servers.

<script type="module" src="https://cdn.jsdelivr.net/npm/@friendlycaptcha/sdk@1.0.2/site.min.js" async defer></script>
<script nomodule src="https://cdn.jsdelivr.net/npm/@friendlycaptcha/sdk@1.0.2/site.compat.min.js" async defer></script>
<form action="https://api.letterpost.eu/f/k3v9q2" method="POST">
  <label>Email <input type="email" name="email" required></label>
  <label>Message <textarea name="message" required></textarea></label>
  <div class="frc-captcha" data-sitekey="YOUR_SITE_KEY"></div>
  <button type="submit">Send</button>
</form>

With Verify in the EU, the widget gets data-api-endpoint="eu" as well.

What can go wrong

Error code Meaning
captcha_missing The form sent no captcha answer. Check that the widget is inside the <form>.
captcha_failed The answer was wrong, expired or already used.
captcha_unavailable The captcha could not be checked right now. Try again.