Get an endpoint Sign in

Docs Moving from Formspree

Bay 12Bring your forms

#Moving from Formspree

sendm8 reads the same field names as Formspree, so a plain HTML form moves with a one-line change: the action URL. Code that sends forms with JavaScript needs a small change to how it reads errors.

Moving a form

  1. Get a sendm8 endpoint. Create a form in the dashboard and copy its URL, or skip signing up and use https://sendm8.com/f/you@example.com.
  2. Swap the URL everywhere the form posts to https://formspree.io/f/….
  3. Send a test submission and check it arrives where you expect. Then add Discord, Slack, Telegram or webhooks if you like.
contact.html
<form action="https://sendm8.com/f/k3x9q2m7ab" method="POST">
  <input name="email" type="email" required>
  <textarea name="message"></textarea>
  <input type="hidden" name="_subject" value="New enquiry">
  <input type="text" name="_gotcha" style="display:none">
  <button>Send</button>
</form>

What maps to what

Formspree features and their sendm8 equivalents
Formspreesendm8
https://formspree.io/f/{id}https://sendm8.com/f/{id}, or https://sendm8.com/f/{your email} with no account
_replyto or email, _subject, _next, _gotcha, _ccThe same. _next must be on one of the form’s allowed domains, and _cc only copies addresses verified in your account.
Other underscore fieldsIgnored and not stored.
JSON success: { ok: true }{ ok: true, id }
JSON errors: an errors array{ ok: false, error: { code, message } } with a matching HTTP status. AJAX / fetch.
@formspree/react (useForm)A few lines of fetch, below. The package only talks to Formspree.
@formspree/ajax and data-fs-* attributesThe helper script and data-sendm8 attributes. AJAX without writing JavaScript.

JavaScript and React

contact.js
const res = await fetch("https://sendm8.com/f/k3x9q2m7ab", {
  method: "POST",
  body: new FormData(form),
  headers: { Accept: "application/json" },
});
const result = await res.json();

if (result.ok) {
  showThanks();
} else {
  // Formspree: result.errors.map((e) => e.message)
  showError(result.error.message);
}

Migrating with an AI assistant

These docs are also published as Markdown for AI assistants: /llms.txt lists every section, and /llms-full.txt has all of them in one file. Create your sendm8 forms first (an assistant can’t do that for you), then give it a prompt like this in the app you’re migrating.

prompt.txt
Migrate this app's forms from Formspree to sendm8. Read https://sendm8.com/llms-full.txt first.

Endpoint mapping (Formspree → sendm8):
- https://formspree.io/f/xyzabcde → https://sendm8.com/f/k3x9q2m7ab

1. Find every Formspree usage: "formspree.io", "@formspree/react", "@formspree/ajax",
   data-fs-* attributes, and environment variables holding Formspree form IDs.
2. HTML forms: change only the action URL. Field names stay the same.
3. JavaScript submissions: POST to the sendm8 URL with "Accept: application/json".
   Success is { ok: true, id }. Failure is { ok: false, error: { code, message } }:
   show error.message. Update any code that reads Formspree's errors array.
4. Replace @formspree/react and @formspree/ajax with fetch (or the sendm8 helper script),
   keeping the same loading, success and error states. Then remove the packages.
5. Don't change styling, copy or field names.
6. List every file you changed, and anything you couldn't migrate.