How to Set Up Contact Forms on a Static Site (Without a Backend)

Static sites lack server-side form processing by definition — but functional contact forms are still achievable through a few practical approaches. This guide covers the main options.

The Core Challenge

An HTML form needs somewhere to submit data to — a static site has no server-side code to receive and process that submission (send an email, save to a database) without adding some form of backend, however minimal.

Option 1: A Lightweight Serverless Function

exports.handler = async (event) => {
  const { name, email, message } = JSON.parse(event.body);
  await sendEmail(name, email, message);
  return { statusCode: 200, body: JSON.stringify({ success: true }) };
};

A minimal serverless function (deployable to various providers, or self-hosted, see How to Build and Secure a REST API on a VPS for a small dedicated endpoint on your own VPS) handles just the form submission, without needing a full traditional backend for your entire site.

Option 2: A Small Dedicated Endpoint on Your VPS

app.post('/api/contact', async (req, res) => {
  const { name, email, message } = req.body;
  await sendMail({ to: '[email protected]', subject: `Contact from ${name}`, text: message });
  res.json({ success: true });
});

Since your static site is likely already hosted on a VPS, running one small API endpoint alongside it (see How to Send Email from a VPS Without Getting Blacklisted for the email-sending considerations) is a genuinely simple, self-hosted option.

Option 3: A Dedicated Form-Handling Service

Several third-party services exist specifically for handling static site form submissions — your form action points directly to their endpoint, and they handle spam filtering and email delivery; simplest option if you'd rather not build/maintain even a minimal backend yourself.

Basic Form HTML (Works with Most Approaches)

<form action="/api/contact" method="POST">
  <input type="text" name="name" required>
  <input type="email" name="email" required>
  <textarea name="message" required></textarea>
  <button type="submit">Send</button>
</form>

Handling the Submission with JavaScript (For a Better UX)

form.addEventListener('submit', async (e) => {
  e.preventDefault();
  const response = await fetch('/api/contact', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(Object.fromEntries(new FormData(form))),
  });
  if (response.ok) showSuccessMessage();
});

A JavaScript-handled submission avoids a full page reload, providing a smoother user experience than a traditional form POST-and-redirect flow.

Adding Spam Protection

See How to Add CAPTCHA and Rate Limiting to a Contact Form to Stop Spam — contact forms are a common spam target regardless of which backend approach you use; add appropriate protection (honeypot fields, rate limiting, or CAPTCHA) rather than leaving the endpoint unprotected.

Validating Input Server-Side

See How to Implement API Request Validation — validate submitted data server-side (email format, required fields, reasonable length limits) even if you have client-side validation too, since client-side checks can always be bypassed.

Common Errors

Form submissions never arrive despite no visible error — check that your backend endpoint's CORS configuration allows requests from your static site's actual domain, and verify email sending (see How to Send Email from a VPS Without Getting Blacklisted) is genuinely working, not silently failing.

Continue Reading

Browse more articles in Static Site Hosting & Frontend Deployment.

  • static site contact form, jamstack form handling, serverless contact form, form submission without backend
  • 0 Користувачі, які знайшли це корисним
Ця відповідь Вам допомогла?

Схожі статті

How to Host a Static Website on a VPS with Nginx

Static websites — plain HTML, CSS, and JavaScript with no server-side processing —...

How to Deploy a Next.js Application on a VPS

Next.js supports several deployment modes — fully static export, server-side rendering with...

How to Deploy a Static Site Built with Astro, Hugo, or Jekyll

Static site generators (Astro, Hugo, Jekyll) produce plain HTML/CSS/JS at build time —...

How to Optimize Images for Web Performance

Images are typically the largest contributor to page weight and load time. This guide covers...

How to Set Up a Jamstack Site with a Headless CMS Backend

The Jamstack architecture (JavaScript, APIs, Markup) combines a pre-built static frontend with a...