Mailto Form vs Form Backend: Why mailto: Fails and What to Use
A mailto form opens the visitor's email app instead of sending data. Learn why mailto: forms fail, how to send form data to email reliably, and how to migrate.
6 min read

A mailto form uses action="mailto:you@example.com", which does not send anything: it asks the visitor's device to open their email app with a prefilled draft, and the message only arrives if they have a mail client set up and press send. To reliably send form data to email, point the form at a form backend instead. It is a one-line change.
The mailto form action is popular because it needs no server. That convenience hides several problems that cost real messages, often without the site owner ever noticing.
How a mailto form action behaves
Here is a typical example:
<form action="mailto:hello@example.com" method="POST" enctype="text/plain">
<input type="text" name="name">
<input type="email" name="email">
<textarea name="message"></textarea>
<button type="submit">Send</button>
</form>When someone clicks Send, the browser does not make a network request to anyone. Instead it hands a mailto: URL to the operating system, which opens whatever is registered as the default email handler. Depending on the browser, the form fields end up in the body of a new draft, sometimes as name=Ada lines and sometimes URL-encoded into a single unreadable string.
What happens next is entirely up to the visitor and their device.
The problems with mailto forms
It depends on the visitor's email client
Many people read email in a browser tab, not a desktop app. If no handler is configured, clicking submit does nothing, opens an app they have never set up, or shows a system prompt asking which app to use. Each of those is a point where people give up.
There is no confirmation
Your site never learns whether the message was sent. The visitor sees a draft, not a "thanks" message, and may assume it went through. If they close the draft, the lead is gone and you have no record it ever existed.
Behavior varies by browser and device
Browser support for mailto: as a form action has always been inconsistent. Encoding differs, some ignore the body, and mobile browsers may switch apps abruptly, interrupting the visitor. Testing on your own machine tells you little about what your visitors experience.
Your address is exposed
The email address sits in plain text in your HTML, where address-harvesting bots can collect it. Expect more spam to that inbox over time.
No files, validation or routing
You cannot reliably attach uploaded files, you get no server-side validation, and there is no way to forward submissions to Slack, a spreadsheet or a CRM.
No spam filtering, no history
Every message lands directly in your mailbox with no filtering, and there is no searchable archive or export outside your email client.
| Need | mailto form | Form backend |
|---|---|---|
| Works for webmail users | Often not | Yes |
| Confirmation to visitor | No | Redirect or inline message |
| Record of every submission | No | Dashboard and export |
| Hides your email address | No | Yes |
| File uploads | No | Yes |
| Spam protection | No | Yes |
| Integrations | No | Webhooks, Sheets, Slack and more |
Other mailto link problems to know about
A plain mailto: link (as opposed to a form action) has fewer problems because visitors expect it to open email. It still exposes your address and still fails for people without a configured handler. Keep one as a secondary contact option if you like, but do not make it the only path for leads.
Alternatives for an HTML form to send email
- Hosted form backend: the form posts to a service URL that emails you. No code to maintain, works on any host. This is the closest drop-in replacement.
- Your own server route or serverless function: parse the request and send through a transactional email provider. Flexible, but you own deliverability, spam filtering and storage.
- An embedded form builder: reliable, though the form is hosted by the vendor and styled their way.
For static sites, the tradeoffs are covered in static website forms.
What to check before you switch
Whichever alternative you pick, run through these before retiring the mailto form:
- Deliverability: notifications should come from a sender with proper DNS records, so they reach your inbox rather than junk.
- Reply-To: you should be able to hit Reply and answer the visitor directly, without copying their address.
- Confirmation: visitors need a clear success state, either a thank-you page or an inline message.
- Spam handling: suspected spam should be filtered or quarantined, not mixed into your inbox.
- Record keeping: every submission should be stored somewhere searchable, so a missed email never means a missed lead.
- Privacy: know where submission data is stored and for how long, and update your privacy notice to match.
If a provider cannot answer each of these clearly, keep looking. The whole point of moving off a mailto form is that you stop guessing whether messages arrived.
Migrating from mailto to a form backend
- Create a form with a form backend and copy the endpoint URL.
- Replace
mailto:in theactionwith that URL and removeenctype="text/plain". - Make sure each field has a
nameattribute and addrequiredwhere needed. - Add a honeypot field and, optionally, a subject and redirect.
- Deploy and send a test submission, then remove your email address from the page source.
The updated form:
<form action="https://formsubmit.app/f/YOUR_FORM_ID" method="POST">
<label for="name">Name</label>
<input id="name" type="text" name="name" required>
<label for="email">Email</label>
<input id="email" type="email" name="email" required>
<label for="message">Message</label>
<textarea id="message" name="message" required></textarea>
<input type="hidden" name="_subject" value="Website contact form">
<input type="hidden" name="_redirect" value="https://example.com/thanks">
<input type="text" name="_gotcha" tabindex="-1" autocomplete="off" style="display:none">
<button type="submit">Send</button>
</form>The visitor now gets a clear thank-you page, you get an email with a Reply-To pointing at the submitter, and bots that fill the hidden _gotcha field are dropped silently. If you want to reply to a different field, _replyto overrides it.
If your site uses React
The same migration in a component, using fetch and the JSON response:
import { useState } from "react";
export function ContactForm() {
const [status, setStatus] = useState("idle");
async function onSubmit(e: React.FormEvent<HTMLFormElement>) {
e.preventDefault();
setStatus("sending");
const res = await fetch("https://formsubmit.app/f/YOUR_FORM_ID", {
method: "POST",
body: new FormData(e.currentTarget),
headers: { Accept: "application/json" },
});
const data = await res.json();
setStatus(data.ok ? "sent" : "error");
}
if (status === "sent") return <p>Thanks, we will be in touch.</p>;
return (
<form onSubmit={onSubmit}>
<input name="name" required />
<input name="email" type="email" required />
<textarea name="message" required />
<input name="_gotcha" tabIndex={-1} autoComplete="off" style={{ display: "none" }} />
<button disabled={status === "sending"}>Send</button>
{status === "error" && <p role="alert">Something went wrong. Please try again.</p>}
</form>
);
}Errors come back as { "ok": false, "error": { "code", "message" } }, so you can show the message directly. The React contact form guide has a fuller version.
Make the switch
FormSubmit gives you an endpoint that replaces a mailto form action in one line, with email notifications, spam protection and an optional autoresponder so visitors get a confirmation in their own inbox. The Free plan needs no credit card. Build your form with the form generator or compare plans on the pricing page.
Last updated .


