All articles

HTML Form to Email: Send Submissions Without a Backend (2026)

October 10, 2026·By GoodInbound team

Send HTML form submissions to your inbox without PHP or a server: the form markup, a fetch() version, redirects, free endpoints compared, and how to keep spam out.

HTML can't send email by itself. To get form submissions in your inbox without running a server, point the form's action at a hosted form endpoint and submit with POST. The endpoint receives the fields, stores them, and emails you. This guide covers the markup, a JavaScript version, thank-you redirects, the free endpoints worth comparing, and how to stop spam and sales pitches from filling the inbox you just connected.

GoodInbound is a form backend built for exactly this. Point your HTML form's action at a GoodInbound endpoint and you get more than an email:

  • Spam and unsolicited pitch protection, from bots and from people, with every submission labeled and a reason attached.
  • Contact enrichment on real leads.
  • Notifications by email, Slack, or Telegram.
  • Built-in workflows that sync or feed each submission to the rest of your pipeline: your CRM, webhooks, and ad platforms.

The free plan covers 500 submissions a month. Start free, or follow the steps below with any endpoint.

Why action="mailto:" doesn't work

<form action="mailto:you@example.com"> doesn't send anything over the network. It asks the visitor's browser to open their own email app with the form data pasted in. In practice:

  1. Nothing happens for many visitors. If no mail app is set up, which is common on work laptops and phones, the browser does nothing or shows an error.
  2. The visitor still has to press send. They leave your page, see a half-formatted draft, and many give up.
  3. The data arrives mangled. Browsers encode mailto: form data differently, so fields often land as one long URL-encoded line.
  4. Your address is in the page source. Scrapers collect it, and the spam starts.

A form endpoint fixes all four: the browser makes a normal POST request, and the email is sent from a server you don't have to run.

Step 1: Build the form

Any standard HTML form works. Two rules matter: use method="POST", and give every input a name, because the name is what the endpoint reads.

<form action="https://goodinbound.com/api/v1/forms/your-project/contact" method="POST">
  <label for="name">Name</label>
  <input id="name" name="name" type="text" required>

  <label for="email">Email</label>
  <input id="email" name="email" type="email" required>

  <label for="message">Message</label>
  <textarea id="message" name="message" rows="5" required></textarea>

  <!-- Honeypot: hidden from people, filled in by simple bots -->
  <input name="website" type="text" tabindex="-1" autocomplete="off" aria-hidden="true" style="display:none">

  <button type="submit">Send</button>
</form>

required and type="email" let the browser check the basics before anything is sent. They don't stop bots, which can post to your endpoint without loading the page at all.

Step 2: Connect it to your inbox

With GoodInbound, the endpoint comes from a form you create in the dashboard:

  1. Create a form and add the fields you collect, for example Name, Email, and Message. Each field's ID comes from its label: Name becomes name, and Full name would become full_name.
  2. Open the form's settings and copy the HTML Action URL. It looks like https://goodinbound.com/api/v1/forms/your-project/contact.
  3. Paste it into your form's action, and make each input's name match a field ID. Inputs that don't match a field are ignored.
  4. Choose the email address for notifications, then decide what reaches it. Every submission is labeled lead, review, spam, junk, or bot, and each label can notify you instantly, in a daily summary, or not at all. By default, leads and review arrive instantly, spam goes into a daily summary, and junk and bots are never sent.

The free plan covers 500 screened submissions a month with unlimited forms. Every submission is also kept in the inbox, so nothing is lost if an email goes astray.

Step 3: Send a thank-you page or a message

A plain HTML form leaves the page when it submits, so the visitor needs somewhere to land. Without one, they see the endpoint's default confirmation page.

  • GoodInbound: set a Redirect URL under the form's After submit settings, or a custom thank-you title and message if you'd rather not redirect.
  • FormSubmit: add a hidden _next input with the URL of your thank-you page.
  • Formspree: custom redirects need a paid plan. Free forms show Formspree's own confirmation page.

Send the form with JavaScript instead

To keep the visitor on the page and show a message in place, submit with fetch(). Ask for JSON and the endpoint returns the result instead of redirecting:

<form id="contact" action="https://goodinbound.com/api/v1/forms/your-project/contact" method="POST">
  <!-- same fields as above -->
  <p id="status" role="status"></p>
</form>

<script>
  const form = document.getElementById("contact");
  const status = document.getElementById("status");

  form.addEventListener("submit", async (event) => {
    event.preventDefault();
    status.textContent = "Sending…";
    try {
      const res = await fetch(form.action, {
        method: "POST",
        headers: { Accept: "application/json" },
        body: new FormData(form),
      });
      if (!res.ok) throw new Error(String(res.status));
      status.textContent = "Thanks, we'll be in touch.";
      form.reset();
    } catch {
      status.textContent = "That didn't send. Please try again.";
    }
  });
</script>

Sending FormData keeps file inputs working. With GoodInbound, the JSON response also includes the submission's label and reason, for example {"label": "lead", "reason": "Asks about pricing for a team of 12"}. You can use it to show a different follow-up to real leads, like a booking link.

Free form-to-email services compared

Most endpoints work the same way. They differ in how much the free plan covers and what they do about spam. The figures below are from each product's own pricing page and docs, checked October 2026.

Service Free submissions Setup Spam protection on the free plan
GoodInbound 500 a month, screened Create a form, copy its action URL Checks behavior, network, and identity, and labels every submission (the message check that catches pitches is on Pro)
Formspree 50 a month Form endpoint ID in the action reCAPTCHA and basic automated filtering
Web3Forms 250 a month Verify your email, add an access key input hCaptcha or a honeypot (reCAPTCHA and Turnstile are on Pro)
FormSubmit No stated limit Your email address in the action, then confirm it once reCAPTCHA, a _honey field, and a phrase blacklist

A few differences matter more than the headline number:

  • Formspree's free plan keeps 30 days of history and leaves out redirects, file uploads, and webhooks. See Is Formspree free? for the full breakdown, or Formspree alternatives for a side-by-side.
  • Web3Forms puts webhooks, file uploads, reCAPTCHA, and Turnstile on Pro, $149 a year. More in Web3Forms alternative.
  • FormSubmit is free and needs no account, but your email address sits in the page source and submissions are kept for 30 days. More in FormSubmit alternative.

Keep spam out of the inbox you just connected

A public form endpoint gets found. Within days of going live, most contact forms start receiving three kinds of junk:

  1. Bots that post straight to the endpoint, often without loading your page.
  2. Fake or throwaway sign-ups using disposable addresses or someone else's email.
  3. People selling to you: SEO agencies, dev shops, link sellers, and recruiters with real names and real inboxes.

(Using a Google Form instead? See how to stop Google Forms spam.)

CAPTCHAs and honeypots handle a share of the first group. They do nothing about the third, because a person can solve a CAPTCHA. That's why so many forms with reCAPTCHA turned on still get ten pitches a day.

GoodInbound screens every submission in five steps: your own rules, how the form was filled in, the network it came from, the email identity, and what the message actually asks for. The last step uses privacy-first open-source models running on Cloudflare and is part of the Pro plan; Free runs the other checks. Each submission gets a label and a one-line reason. Nothing is deleted, so anything screened out by mistake can be rescued in one click, and your notification rules decide which labels reach your email at all.

Troubleshooting: the form submits but no email arrives

  • Check the field names. Inputs need a name. With GoodInbound, names must match the form's field IDs, or the values are ignored.
  • Confirm the address. FormSubmit sends a confirmation email the first time a form is used, and nothing is delivered until you click it.
  • Look in your spam folder. Mail from shared form services is often filtered. Add the sending address to your contacts once and later notifications land normally.
  • Check the label. In GoodInbound, open the form's inbox. If the submission is there labeled spam or junk, your notification rules held it back on purpose.
  • Check your plan's limit. Free plans cap monthly submissions. Formspree, for example, emails you at 50%, 75%, and 90% of the allowance, so check for those warnings.

FAQ

Can HTML send an email by itself?

No. HTML has no way to reach a mail server. A form either opens the visitor's email app with mailto: or posts to a server or hosted endpoint that sends the email for you.

How do I send HTML form data to an email without PHP?

Point the form's action at a hosted form endpoint with method="POST", give every input a name, and set the notification email in the service's dashboard. The service receives the data and sends the email, so there's no PHP mail() or SMTP setup.

Is there a free form-to-email service?

Yes. GoodInbound's free plan covers 500 screened submissions a month. Web3Forms covers 250, Formspree covers 50, and FormSubmit states no limit but keeps submissions for only 30 days.

Does reCAPTCHA stop contact form spam?

It stops a share of automated bots. It doesn't stop a person, so sales pitches and manual spam still come through. Screening that reads the message catches those; in GoodInbound that check is part of Pro.

How do I show a thank-you message without leaving the page?

Submit the form with fetch() and an Accept: application/json header, then update the page when the request succeeds, as in the JavaScript example above.

Switch in 5 minutes

Setup with your agents