Skip to content

Software Engineering

Formspree alternatives and self-hosted form backends: how to handle contact forms

Options for handling form submissions from a static or Jamstack site: hosted form services, serverless functions, and a self-hosted form backend, with spam protection and privacy notes.

By · Published · 3 min read

Short answer: a static site cannot receive a form post by itself, so you need a backend. The options are a hosted form service, your own serverless function or small API, or a self-hosted form backend. Hosted services are quickest. A self-hosted backend suits you if you run many sites, want submissions in your own database, or need to control where personal data goes.

Why does a contact form need a backend?

A form sends an HTTP request to a URL. Static hosting serves files and cannot process that request, send you an email or store the message. Something must receive it, validate it, filter spam, store it and notify you.

What are the main options?

Hosted form services

Services such as Formspree and its competitors give you an endpoint URL. You set it as the form action, and they email you submissions. Free tiers usually cap monthly submissions, and paid plans add file uploads, integrations and spam filtering.

  • Pros: minutes to set up, no servers, built-in spam tools.
  • Cons: recurring cost at scale, third party holds your submissions, limits on volume, and you depend on their service.

A serverless function

Write a function on your hosting platform that accepts the post and sends mail through a transactional email service.

export async function POST(req: Request) {
  const data = await req.formData();
  if (data.get("website")) return new Response(null, { status: 204 }); // honeypot filled: bot
  const email = String(data.get("email") ?? "");
  const message = String(data.get("message") ?? "").slice(0, 5000);
  if (!/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(email) || !message) {
    return new Response("Invalid", { status: 400 });
  }
  await sendMail({ to: "[email protected]", replyTo: email, subject: "Contact form", text: message });
  return Response.redirect("/thanks", 303);
}
  • Pros: cheap, flexible, you control logic.
  • Cons: you maintain it, and you must add spam protection and rate limiting yourself.

A self-hosted form backend

One small service, deployed once, that serves every form on every site you own. Each site gets a key. Submissions land in your own PostgreSQL database, with email or webhook notifications. That is what Submify is: one API key, every form on every site, stored in your own database.

  • Pros: no per-submission fees, one inbox and database for all sites, you decide retention and access.
  • Cons: you host it, secure it and back it up. See the self-hosting checklist.

How do you stop spam?

  • Honeypot field: a hidden input humans leave empty. Cheap and catches simple bots.
  • Rate limiting by IP.
  • CAPTCHA alternatives such as Cloudflare Turnstile or hCaptcha for abuse that gets through.
  • Server-side validation of every field. Never trust the browser.
  • Block header injection by rejecting newlines in fields that end up in email headers.
  • Reject oversized bodies.

What about privacy?

A contact form collects personal data. Say what you collect and why, how long you keep it, and where it is stored. If you use a third-party service, it is a processor of your visitors' data, and laws like the GDPR or India's DPDP Act may expect you to have terms with them. Delete old submissions on a schedule.

How do you choose?

  • One small site, low volume: hosted free tier.
  • A few sites with moderate volume and some technical skill: serverless function.
  • Many sites, client work, or data ownership matters: self-hosted backend.

Test the whole path, including email deliverability, because a form that silently fails costs you leads.

Author

Raktim Ranjit is a software engineer and the founder of NodeDR Infotech. He builds and maintains the software described here.

Have something in mind?

Let’s build something useful.

Tell me about the idea, product, or workflow you’re working through.

Tap to say hello