Dispatch Web
All posts

Forms without a server: how an enquiry reaches your inbox

Follow an enquiry from the browser to your email, see where spam is stopped, and learn the three places a message can go missing. This site's own form is the worked example. Fully referenced.


The contact form is the part of a marketing site that has to work every time, and the part most often broken. A visitor presses send, sees “thanks”, and nothing arrives. Nobody notices for weeks. This post follows an enquiry from the browser to your inbox, using the brief builder on this site as the example, and names the places messages go missing and the fix for each.

What a form actually does

A form looks like part of the page, but its job is to send a message to a computer somewhere else. MDN, the reference maintained by Mozilla, puts it plainly: “An HTML form on a web page is nothing more than a convenient user-friendly way to configure an HTTP request to send data to a server.”[1] When you press send, the browser packages what you typed and posts it. Something on the other end has to receive it, decide whether it is genuine, and turn it into an email.

A static site is a set of files, and files cannot read a message or send an email. So a static site needs one small piece of server-side code for its form, and that code needs somewhere to run.

Where our form handler runs

We do not run a server for this. The site is deployed to Cloudflare Pages, and the form handler is a Pages Function. Cloudflare describes Functions as a way to “deploy server-side code to enable dynamic functionality without running a dedicated server”[2], and lists “handling form submissions” as one of the things they are for[2]. The code runs on Cloudflare’s network only when a form is posted. There is no machine to patch and nothing idling between enquiries.

The handler on this site reads the submission, applies two spam checks, validates the fields, and hands the message to an email service. Each step can say no, and when it says no the form tells the visitor why.

The journey, step by step

  1. The browser posts the message. The brief builder collects your answers over several steps and posts them, with your name and email, to the form endpoint on this site. Until then your draft stays on your own device.
  2. The honeypot is checked. The form has one extra field that a person never sees. It is moved off screen, skipped by the keyboard and marked as hidden to screen readers. Scripts that fill in every field they find fill this one too. If it contains anything, the handler replies “ok” and quietly discards the message, so the script believes it succeeded and has no reason to try harder.
  3. Turnstile is verified. On the send step the form shows a small Cloudflare Turnstile widget, which is “Cloudflare’s smart CAPTCHA alternative”[3]. It “works without showing visitors a CAPTCHA”[3]; instead, “we run a series of small non-interactive JavaScript challenges to gather signals about the visitor or browser environment”[3]. The widget produces a token, and the browser sends that token with the message. The handler then asks Cloudflare whether the token is real. This server-side check is not optional, because “Tokens can be forged. An attacker can submit any string to your form endpoint without completing a challenge.”[4] Each token is also “valid for 300 seconds (5 minutes) after generation”[4] and “can only be validated once”[4], so a captured token cannot be replayed. A missing or failed token gets a “please complete the verification” reply and the widget resets.
  4. The fields are validated. MDN’s rule is blunt: “All data that comes to your server must be checked and sanitized. Always. No exception.”[1] The handler trims every field, caps its length, requires a name, and requires an email address that has the shape of an email address. Anything that fails gets a plain-English error and nothing is sent.
  5. The message is assembled. The answers are laid out as plain text with the time received in Perth. Your email address is set as the reply-to, so answering the enquiry is one click.
  6. The message is sent through Resend. Resend is “the email API for developers”[5]. The handler makes one request to it with the text, the recipients and the sending address. If Resend accepts it, the form shows a success message. If it does not, the form says sending failed and asks the visitor to try again or email us directly.
  7. The receiving mail server decides. Resend hands the message to the recipient’s mail provider, which checks who sent it before deciding between the inbox, the junk folder, or nowhere. That check is the step most sites never configure.

The important property of the whole path is that every failure is loud. A form that returns “thanks” while the message goes nowhere is worse than no form.

Two spam checks, and why both

The honeypot catches crude scripts that fill every field, at no cost to the visitor. Turnstile catches the rest. The classic defence, a CAPTCHA, is described by OWASP as a test that works “by presenting some test that is easy for humans to pass but difficult for computers to pass”[6]. Turnstile keeps the idea and drops the puzzle. It also keeps out of your message: “Turnstile does not access, store, or transmit user communications, form entries, or other page inputs.”[3]

A visitor on a phone sees a form, a small tick, and a confirmation. They do not pick out traffic lights.

Where messages go missing

The receiving mail provider has to believe the message is from who it says it is from. Three records in your domain’s DNS do that work.

SPF lets a domain publish which servers may send its mail. The standard puts it this way: “Compliant ADMDs publish Sender Policy Framework (SPF) records in the DNS specifying which hosts are permitted to use their names.”[7] ADMD is the standard’s term for the organisation that owns the domain.

DKIM adds a signature. It “permits a person, role, or organization that owns the signing domain to claim some responsibility for a message by associating the domain with the message”[8], and the claim “is validated through a cryptographic signature and by querying the Signer’s domain directly to retrieve the appropriate public key”[8].

DMARC says what to do when the first two fail. Cloudflare’s summary is one sentence: it “Tells receiving servers what to do when SPF or DKIM checks fail (for example, reject or quarantine the email).”[9] Without these records, “anyone can send email that appears to come from your domain”[9].

Google’s sender guidelines for Gmail require every sender to “Set up SPF or DKIM email authentication for your sending domains”[10], and warn that “Messages that aren’t authenticated with these methods might be marked as spam or rejected with a 5.7.26 error.”[10] An enquiry sent from an unverified domain can vanish before you ever see it.

Resend enforces this before you send anything: “You must add and verify at least one domain to send emails with Resend.”[11] Verification means adding the records it generates. You “Provide the DKIM and SPF configurations (TXT and MX or CNAME records) to your DNS provider”[12], and “These records must match exactly what Resend generated.”[12] Once verified, Resend recommends going further: “After your domain is verified, you can then implement DMARC to build additional trust in your domain and protect against email spoofing.”[12] This site sends from a domain verified in exactly that way.

The table lists the failures we see most, and the fix for each.

Where it goes missing What the visitor sees The fix
No delivery configured; the handler has nowhere to send On this site: an error, an email address to use instead, and their answers saved on their device. On many sites: “thanks”, and silence The handler must refuse loudly when it cannot send. Test it on launch day and again after any hosting change
Sending domain not authenticated; mail is rejected or junked “Thanks”. The email never arrives, or lands in junk Verify the sending domain with SPF and DKIM records, then add DMARC[10][12]
Junk folder on your side; the message arrived but was filtered “Thanks”. You find it a month later Add the sending address to your safe senders, and check junk during the first week after launch
Spam check rejects a real person A verification error Turnstile resets the widget for another attempt; the honeypot never triggers on a person. Keep a plain email address on the site as the fallback

Every row has the same lesson: silence is the failure mode. Each step should either succeed or say why it did not.

What “tested contact form” means in our launch

Our launch stage includes a tested contact form. The test is the journey above run end to end: a real submission from a browser, a real email in the inbox, a reply-to that works, both spam checks confirmed to reject what they should, and the sending domain verified before the site goes live. The previous post explained why the form is one of the few React islands on this site; this post is why the code behind it is short and strict.

If you have a site now, send yourself an enquiry through it today. If nothing arrives, your customers found the problem first. If you are planning a build, the brief builder is the form described above, and you will get a reply from a person within two business days.

Reference list

All sources accessed 30 July 2026.

  1. Mozilla (n.d.) Sending form data. MDN Web Docs. https://developer.mozilla.org/en-US/docs/Learn_web_development/Extensions/Forms/Sending_and_retrieving_form_data
  2. Cloudflare (n.d.) Functions. Cloudflare Pages documentation. https://developers.cloudflare.com/pages/functions/
  3. Cloudflare (n.d.) Cloudflare Turnstile. Cloudflare Docs. https://developers.cloudflare.com/turnstile/
  4. Cloudflare (n.d.) Server-side validation. Cloudflare Turnstile documentation. https://developers.cloudflare.com/turnstile/get-started/server-side-validation/
  5. Resend (n.d.) Introduction. Resend documentation. https://resend.com/docs/introduction
  6. OWASP Foundation (n.d.) Blocking Brute Force Attacks. OWASP Community. https://owasp.org/www-community/controls/Blocking_Brute_Force_Attacks
  7. Kitterman, S. (2014) RFC 7208: Sender Policy Framework (SPF) for Authorizing Use of Domains in Email, Version 1. Internet Engineering Task Force. https://datatracker.ietf.org/doc/html/rfc7208
  8. Crocker, D., Hansen, T. and Kucherawy, M. (eds) (2011) RFC 6376: DomainKeys Identified Mail (DKIM) Signatures. Internet Engineering Task Force. https://datatracker.ietf.org/doc/html/rfc6376
  9. Cloudflare (n.d.) Security records. Cloudflare DMARC Management documentation. https://developers.cloudflare.com/dmarc-management/security-records/
  10. Google (n.d.) Email sender guidelines. Gmail Help. https://support.google.com/mail/answer/81126
  11. Resend (n.d.) Domains: Introduction. Resend documentation. https://resend.com/docs/dashboard/domains/introduction
  12. Resend (n.d.) Add a domain. Resend documentation. https://resend.com/docs/add-a-domain

Unfamiliar word? Every term in this post is defined in one sentence in the glossary.

Written by Dispatch Web. Corrections and questions: send them through the brief builder and mark them as a note; they reach the same board.