HTML form without a backend

    An HTML form that reaches a real inbox. No server.

    Design the form in mailnix, publish it, paste the snippet into any static site. Submissions land in a spam-scored inbox and email you at the addresses you verified. Works on Astro, Hugo, Eleventy, plain HTML, any static host.

    Start freemailnix Forms

    The job

    A static-site contact form usually means picking a form-backend vendor (Formspree, Web3Forms, Getform, Basin, Netlify Forms) that emails you the fields. mailnix is the option where the fields land in a real inbox with spam scoring, status workflow, retention, CSV export, and one-click replies from a dashboard composer. The public submissions endpoint expects a JSON body, so a plain <form action> POST needs a six-line fetch shim. If a truly zero-JavaScript form is a hard requirement, embed the hosted mailnix form page in an iframe.

    The code

    index.html

    <!-- Contact form. Submissions land in your mailnix inbox with spam
         scoring, owner-notification emails, and per-submission replies.
         No server, no database, no build step required. -->
    <form id="contact">
      <label>Name    <input name="name"    required></label>
      <label>Email   <input name="email"   type="email" required></label>
      <label>Message <textarea name="message" required></textarea></label>
    
      <!-- Honeypot: real visitors never fill this. Bots almost always do. -->
      <input name="website" tabindex="-1" autocomplete="off"
             aria-hidden="true" style="position:absolute;left:-9999px">
    
      <button type="submit">Send</button>
    </form>
    
    <script>
      // The mailnix public endpoint expects a JSON body of the shape
      // { "data": { ...fields, "_mnx_ft": "<fill_time_token>" } }, which a
      // plain <form action> POST cannot produce. This shim fetches the
      // token, reshapes the FormData, and posts it.
      const FORM_ID = "PUBLIC_ID";
      const BASE = "https://api.mailnix.ch/v1/public/forms/" + FORM_ID;
    
      document.getElementById("contact").addEventListener("submit", async (e) => {
        e.preventDefault();
        const form = e.target;
        const fields = Object.fromEntries(new FormData(form));
        if (fields.website) return;             // honeypot tripped, silently drop
        const def = await fetch(BASE).then((r) => r.json());
        const res = await fetch(BASE + "/submissions", {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({
            data: { ...fields, _mnx_ft: def.fill_time_token },
          }),
        });
        form.outerHTML = res.status === 201
          ? "<p>Thanks, we got your message.</p>"
          : "<p>Something went wrong. Please email us instead.</p>";
      });
    </script>
    
    <!-- Zero-JavaScript fallback: embed the hosted mailnix page in an
         iframe, or link straight to it. It is a real HTML form on
         forms.mailnix.ch and needs nothing from your site.
    
         <iframe src="https://forms.mailnix.ch/f/PUBLIC_ID"
                 style="width:100%;height:640px;border:0"
                 loading="lazy"></iframe>
    -->

    Setup, in order

    1. Design the form in the mailnix dashboard (Forms, then New form) with the fields you need.
    2. Publish the form to freeze a version and get a public_id. Draft or paused forms return 404 to the public endpoint on purpose.
    3. Paste the HTML above into your static site and replace PUBLIC_ID with the id from the dashboard.
    4. In the form's settings, add the exact origin of your site (scheme + host, no path) to Allowed origins so cross-origin POSTs pass the check.
    5. Send one real submission and confirm it lands in the Forms inbox with a plausible spam score, then verify at least one owner notify address so future submissions email you.

    What you get on top

    An inbox, not email forwarding

    Formspree, Web3Forms, Basin and friends email you the fields. mailnix keeps every submission with a spam score, a status workflow, per-form retention, CSV export, and per-submission replies.

    Zero-JavaScript fallback

    The hosted form page at forms.mailnix.ch/f/<public_id> is a real HTML form that works with no JavaScript at all. Embed it in an iframe from a Hugo template, an Astro layout, or a plain index.html.

    Honeypot + optional CAPTCHA

    The invisible input in the snippet stops the lazy 80 percent of bots at zero cost. Turn on Turnstile or hCaptcha in the form's settings for the rest. Every submission is spam-scored regardless.

    One product, many static generators

    The endpoint is the same for plain HTML, Astro, Hugo, Eleventy, Jekyll, MkDocs, or any Jamstack framework. Paste the snippet or the iframe and ship.

    Gotchas people actually hit

    • A plain <form action="https://api.mailnix.ch/..."> POST sends application/x-www-form-urlencoded and returns 400 malformed_submission. Use the fetch shim in the snippet (it reshapes into JSON), or use the hosted iframe fallback with no JS.
    • The public_id is not a secret. It appears in every embed and in the page source by design. The security boundary is the Origin allowlist plus rate limits plus optional CAPTCHA.
    • CORS: the endpoint reflects any well-formed Origin, but the form's own Allowed origins list is a second gate. If you copy the snippet to a new domain and forget to add it, submissions come back 403 origin_not_allowed.
    • Honeypot fields catch lazy bots but not sophisticated ones. Turn on Turnstile or hCaptcha in the form settings if a scraper finds you; the endpoint accepts the token as an X-Mailnix-Captcha-Token header or as a _mnx_captcha key inside data.
    • Do not confuse mailnix Forms with mailnix publishable keys. Publishable keys are for browser-safe transactional email sending and DO carry a key value in the Authorization header. Forms uses the public_id in the URL and needs no header auth.
    • mailto: in action= is not a solution. It opens the visitor's mail client (if they have one), exposes your address to scrapers, and roughly half of visitors will simply close the pop-up.

    HTML form without a backend FAQ

    Can I really build a contact form with no backend at all?

    Yes. Point the form at the mailnix public submissions endpoint and mailnix handles storage, spam filtering, and owner notifications. Your site stays fully static; you own zero servers and zero databases.

    Do I need JavaScript?

    The mailnix endpoint expects a JSON body, so posting it directly needs the six-line fetch shim in the snippet. For a completely JavaScript-free form, embed the hosted page at forms.mailnix.ch/f/<public_id> in an iframe or link straight to it.

    Is the form URL a secret?

    No. The public_id is designed to be visible in your page source. The security boundary is the Origin allowlist plus rate limits plus optional CAPTCHA.

    How does mailnix Forms differ from Formspree, Web3Forms, or Netlify Forms?

    Those three forward each submission to your email and stop. mailnix keeps a full inbox with spam scoring, status workflow, CSV export, retention, and per-submission replies, alongside the notification email. An AI assistant can also work the inbox for you through the form_* MCP tools.

    Will submissions email me automatically?

    Yes, to any owner notify address you have verified. Members verify with one click; external addresses use a double-opt-in link. You pick per-address between immediate, hourly digest, or daily digest. The submitter is never emailed automatically; replies to them are always a deliberate per-submission action.

    Where is the data hosted?

    EU data centres in Germany, run by LIMERION GmbH out of Liechtenstein. GDPR-ready by default.

    One HTTP call to get started

    Put a form on your site tonight. Wire your provider when you're ready.