Documentation / Code Examples / Submit a Form to Email (HTML/JS)
HTML & JavaScript

Submit a Form to Email with Plain HTML & JavaScript

The retro way: no framework, no server, no nonsense. Point an HTML form at Formigo and your submissions land in your inbox. Want it slicker? Add a few lines of vanilla JavaScript for inline success and error messages.

How "form to email" works with Formigo

You don't write any backend code. You POST your form to a Formigo endpoint that looks like https://formigo.io/f/your-form, and Formigo delivers each submission to your configured channels. To send a form to email without a backend, connect an Email channel to your form and every submission lands in your inbox - no SMTP, no PHP mail(), no spam-folder gymnastics.

Pure HTML form (no JavaScript)

The simplest HTML form to email

Just an HTML <form> - works in any page, anywhere

This is the whole trick: a standard <form> with action pointing at your Formigo endpoint and method="POST". No JavaScript, no backend. The browser does a full-page submit, Formigo accepts it, and your Email channel forwards it to your inbox. Copy this, change your-form to your form's slug, and you have an HTML form that sends to email.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Contact Us</title>
</head>
<body>
  <h1>Contact Us</h1>

  <!-- Submit this form straight to email via Formigo -->
  <form action="https://formigo.io/f/your-form" method="POST">
    <label for="name">Name</label>
    <input type="text" id="name" name="name" required>

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

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

    <!-- Spam protection: leave the honeypot empty; bots fill it in -->
    <input type="text" name="_formigo_hp" value=""
           style="display:none" tabindex="-1" autocomplete="off">
    <input type="hidden" name="_formigo_t" value="">

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

  <!-- One tiny line to timestamp the submission (optional but recommended) -->
  <script>
    document.querySelector('input[name="_formigo_t"]').value =
      Math.floor(Date.now() / 1000);
  </script>
</body>
</html>

What happens on submit? The browser POSTs the form fields to https://formigo.io/f/your-form. Formigo returns a 2xx success and, because you connected an Email channel, the submission is forwarded to your email address. That's a complete "send form to email" flow with zero backend code.

Progressive JavaScript (fetch)

JavaScript form submission with fetch

No dependencies - pure ES6+ with inline success, error, and rate-limit handling

Want to keep visitors on the page and show a friendly message instead of a full reload? Enhance the same form with a little vanilla JavaScript. We intercept the submit, send the data with fetch, and handle three outcomes: success (2xx), a rate-limit response (429 with a retry_after hint), and everything else. Formigo accepts both form-encoded and JSON and is CORS-enabled, so this works straight from the browser. If JavaScript fails to load, the plain HTML form above still submits to email - true progressive enhancement.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Contact Us</title>
  <style>
    .message { padding: 1rem; margin-top: 1rem; border-radius: 8px; }
    .success { background: #d4edda; color: #155724; }
    .error { background: #f8d7da; color: #721c24; }
  </style>
</head>
<body>
  <h1>Contact Us</h1>

  <!-- Same endpoint as the no-JS version; fetch enhances it -->
  <form id="contact-form" action="https://formigo.io/f/your-form" method="POST">
    <label for="name">Name</label>
    <input type="text" id="name" name="name" required>

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

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

    <!-- Spam protection: honeypot stays empty, timestamp set on load -->
    <input type="text" name="_formigo_hp" value=""
           style="display:none" tabindex="-1" autocomplete="off">
    <input type="hidden" name="_formigo_t">

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

  <div id="status"></div>

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

    // Stamp the submission with the current time when the page loads
    form.elements._formigo_t.value = Math.floor(Date.now() / 1000);

    form.addEventListener("submit", async (e) => {
      e.preventDefault();
      const submitBtn = form.querySelector("button[type=submit]");

      // Collect fields (honeypot + timestamp included automatically)
      const data = Object.fromEntries(new FormData(form));

      submitBtn.disabled = true;
      submitBtn.textContent = "Sending...";
      status.className = "";
      status.textContent = "";

      try {
        const response = await fetch("https://formigo.io/f/your-form", {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify(data)
        });

        if (response.ok) {
          // 2xx: Formigo accepted it and emails your inbox
          status.className = "message success";
          status.textContent = "Thanks! Your message is on its way to our inbox.";
          form.reset();
          form.elements._formigo_t.value = Math.floor(Date.now() / 1000);
        } else if (response.status === 429) {
          // Rate limited: respect the retry_after hint
          const { retry_after } = await response.json();
          status.className = "message error";
          status.textContent = `Whoa, too fast! Try again in ${retry_after} seconds.`;
        } else {
          throw new Error(`Unexpected status ${response.status}`);
        }
      } catch (error) {
        status.className = "message error";
        status.textContent = "Something went wrong. Please try again.";
        console.error("Submit failed:", error);
      } finally {
        submitBtn.disabled = false;
        submitBtn.textContent = "Send Message";
      }
    });
  </script>
</body>
</html>
Success (2xx)

Formigo accepted the submission and forwards it to your Email channel.

Rate limited (429)

Read retry_after from the JSON body and tell the visitor when to retry.

Error

Anything else falls through to a friendly retry message.

About the spam fields

Two hidden fields keep your inbox clean:

  • _formigo_hp - a hidden honeypot. Humans never see it, so it stays empty; bots tend to fill every field, which flags them.
  • _formigo_t - a timestamp set when the page loads. Submissions that arrive impossibly fast look automated.

Both are optional, but recommended. Add them once and Formigo handles the rest, so your "form to email" flow doesn't turn into a "spam to email" flow.

Ready to submit your form to email?

Create a form, connect an Email channel, and paste the snippet above. Submissions land in your inbox in minutes - free forever, no credit card, no backend required.