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 Raktim Ranjit · 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.