HTML contact form that sends email: a complete guide

If you've ever written a contact form in HTML and expected it to send an email, you've probably run into a frustrating discovery: it doesn't, not on its own.
HTML forms are just a way to package data and send it somewhere. The "sending email" part is always done by a server receiving that data and deciding what to do with it. That server might be PHP code you wrote, a Node.js function, or a hosted service, but something has to be on the other end.
This guide covers the whole picture: how HTML forms actually work, what your options are for the "server" part, and how to build a contact form that reliably delivers to your inbox.
How HTML forms actually work
When a user fills out a form and clicks submit, the browser collects all the field values and sends them to whichever URL is in the action attribute, using the HTTP method specified by method.
<form action="https://example.com/contact" method="POST">
<input name="email" type="email" />
<button type="submit">Send</button>
</form>That's it. The browser does a POST request to https://example.com/contact with email=user@example.com in the body. What happens next is entirely up to whatever is running at that URL.
If nothing is running at that URL, you get a 404. If what's running there doesn't send an email, no email gets sent. The HTML itself has no opinion about email.
The mailto: trap
You might have seen this:
<form action="mailto:you@yoursite.com" method="POST"></form>This opens the visitor's desktop email client with a draft pre-filled with the form data. It has a few problems:
- Most people browsing your site aren't logged into a desktop email client
- On mobile, it opens the mail app, often empty or broken
- You have no record of what was submitted
- It looks like a 1998 geocities site
Don't use mailto: for contact forms. It's not a solution; it's an accidental footgun that's survived for decades.
What you actually need
Something has to receive your form submission and send the email. Your options:
| Approach | You maintain | Works on static sites | Setup time |
|---|---|---|---|
| PHP mail() | A PHP server | No | Hours (and headaches) |
| Custom Node.js API | A server + email API key | No | Hours |
| Serverless function | A function + email API key | Yes | 30–60 min |
| Form backend service | Nothing | Yes | 2 min |
For most projects, including static sites, HTML pages, and simple websites, a form backend service is the right call. You point your form's action at a hosted URL, and submissions are stored and emailed to you. No server to maintain, no email API to configure.
The rest of this guide uses Formtorch as the form backend, but the HTML patterns work with any similar service.
Building the form
Here's a complete, accessible HTML contact form:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Contact</title>
</head>
<body>
<form action="https://formtorch.com/f/YOUR_FORM_ID" method="POST">
<div>
<label for="name">Name</label>
<input
id="name"
name="name"
type="text"
placeholder="Jane Smith"
required
autocomplete="name"
/>
</div>
<div>
<label for="email">Email</label>
<input
id="email"
name="email"
type="email"
placeholder="jane@example.com"
required
autocomplete="email"
/>
</div>
<div>
<label for="subject">Subject</label>
<input
id="subject"
name="subject"
type="text"
placeholder="What's this about?"
/>
</div>
<div>
<label for="message">Message</label>
<textarea
id="message"
name="message"
rows="6"
placeholder="Your message…"
required
></textarea>
</div>
<button type="submit">Send message</button>
</form>
</body>
</html>A few things to notice:
label elements with matching for/id pairs: screen readers use these to describe inputs. They also make the label clickable, which expands the tap target on mobile. Always write them.
type="email" on the email field: the browser validates the format before submitting and shows a numeric keyboard on mobile.
required attributes: the browser blocks submission if these fields are empty. It's not a substitute for server-side validation, but it catches honest mistakes immediately.
autocomplete hints: these tell the browser (and password managers) what kind of data goes in each field, enabling autofill. autocomplete="name" and autocomplete="email" are the ones that matter here.
Getting your form endpoint
You need a Formtorch account and a form created in the dashboard.
Create an account
Sign up at formtorch.com. The free plan includes 100 submissions per month, which is plenty for a contact form.
Create a project and form
Click New Project, then New Form. Give the form a name, like "Contact Form". Your endpoint URL is generated immediately.
Copy the endpoint URL
Your endpoint looks like https://formtorch.com/f/abc123. Replace
YOUR_FORM_ID in the form above with the ID from that URL.
Set up your notification email
Go to Form Settings → Notifications, add your email, and confirm it. From this point, every submission sends you an email.
Redirecting after submission
By default, Formtorch shows a generic success page after submission. You'll almost certainly want to send people to your own page:
<form action="https://formtorch.com/f/YOUR_FORM_ID" method="POST">
<!-- Hidden field: controls where users land after submitting -->
<input
type="hidden"
name="_redirect"
value="https://yoursite.com/contact/thank-you"
/>
<!-- your visible fields -->
<input name="name" type="text" required />
<input name="email" type="email" required />
<textarea name="message" required></textarea>
<button type="submit">Send message</button>
</form>Fields with names starting with _ are metadata that control Formtorch's
behavior. They're stripped from the submission before it's stored or emailed
to you.
Your thank-you page can be as simple as a static HTML file with a "Thanks, we'll be in touch." message. It doesn't need to do anything except exist and feel like a confirmation.
Form HTML best practices
A few more things that are easy to skip but worth doing:
Use <label> elements, not placeholder as labels. Placeholder text disappears when you start typing. If you forget what a field is for halfway through, you have to clear it to find out. Labels stay visible.
Group related fields with <fieldset> and <legend>. Not always necessary, but for forms with multiple sections (shipping vs. billing, for example), it helps screen readers group the context.
Don't disable the submit button after one click without visual feedback. If the network is slow, users will click again, assuming it didn't register. Either disable with a spinner or change the button text to "Sending…".
Put novalidate on the form if you're handling validation yourself in JavaScript. Without it, the browser's built-in validation and your JS validation will conflict.
What about spam?
Every publicly accessible contact form gets hit by spam. How quickly depends on how prominent your site is, but it happens to everyone eventually.
Formtorch runs spam detection automatically on every submission. Most spam never reaches your inbox. If you're building a form with custom backend code, read How to prevent spam in contact forms for practical techniques.
Testing your form
Before shipping, test the full path:
- Fill in all required fields and submit. Do you land on your thank-you page?
- Check your Formtorch dashboard. Does the submission appear?
- Check your email. Did the notification arrive?
- Try submitting with required fields empty. Does the browser block it?
- Try submitting with an invalid email. Does the browser catch it?
The dashboard test is worth doing separately from the email check. Sometimes notification emails end up in spam, and seeing the submission in the dashboard confirms the form is working even if the email got filtered.
The full picture
HTML forms are just a delivery mechanism. The action attribute is where you point them, and that URL is what actually handles submissions, stores them, and sends email.
The simplest path to a working contact form that sends email:
- Write a proper HTML form with labels, input types, and
requiredattributes - Set
actionto your Formtorch endpoint URL - Add a
_redirectfield pointing to your thank-you page - Add a verified notification email in your form settings
That's a fully functional contact form. No server, no email API, no backend maintenance.
Ready to set up your form?
Create a free Formtorch account. Your endpoint URL is ready in under two minutes.

