Blog Wire up a contact form with a serverless handler
Wire up a contact form with a serverless handler
TL;DR Point your form at a serverless function or a form API instead of a server. It validates the input, checks for spam, and emails you the message. Your static site stays static, and you get submissions in your inbox without running a backend.
A static site does not mean a site without a working contact form. You just move the server part off your site and onto a small endpoint that runs only when someone submits. Here is the pattern.
The shape of it
Your form posts to an external endpoint instead of a server on your own site. That endpoint, a serverless function you write or a hosted form API, does the work: validate the input, filter spam, and email you the message. Your site stays static; the dynamic bit runs on demand somewhere else.
Point the form at a handler
<form action="https://your-endpoint.example/submit" method="POST">
<input name="name" required />
<input name="email" type="email" required />
<textarea name="message" required></textarea>
<input name="company" class="hidden" tabindex="-1" autocomplete="off" />
<button type="submit">Send</button>
</form>
That company field is a honeypot, hidden from real users. Bots fill it in; people do not.
The handler
A minimal serverless function validates, checks the honeypot, and emails you:
export async function POST(request) {
const data = await request.formData();
if (data.get("company")) return new Response("ok"); // honeypot tripped
if (!data.get("email") || !data.get("message")) {
return new Response("Missing fields", { status: 400 });
}
await sendEmail({
to: "you@example.com",
subject: `Contact from ${data.get("name")}`,
text: data.get("message"),
});
return new Response("Thanks", { status: 200 });
}
Use a form API instead if you would rather not host even this; the idea is the same.
Keep out the spam
- A honeypot field catches most bots for free.
- Validate on the server, not just in the browser, since anyone can post directly to the endpoint.
- Rate-limit so one source cannot flood you.
- Add a captcha only if needed, because it adds friction for real visitors.
Why this fits a static site
The form is the one common dynamic feature a content site needs, and this keeps it small. Your pages stay fast static files, and the only server work happens for a few seconds when someone actually writes to you. No backend to run, patch, or pay for around the clock, just an endpoint that wakes up on submit.
FAQ
How does a static site send a form without a backend?
The form posts to an external endpoint: either a small serverless function you write, or a hosted form API. That endpoint does the server work, validating, filtering spam, and emailing you, so your site itself needs no server.
How do I stop spam without a captcha?
A honeypot field that real users never fill, plus basic rate limiting and validation on the handler, stops most automated spam. Reserve a captcha for when bots get past the simpler measures, since it adds friction for real people.
Where does the message go?
The handler emails it to you, usually through a transactional email service or a form API's built-in delivery. You can also store submissions, but for a simple contact form, emailing yourself is enough.