All resources
Forms to email

How to Send a Confirmation Email to Whoever Filled In Your Form

Auto-reply to the person who submitted your form — and why the obvious shortcut turns your form backend into an open mail relay that anyone can use to email strangers.

The ShipMyForm team

· 5 min read

Short answer: the confirmation has to be sent by your backend, to an address it read out of the submission. The page must never get to choose the recipient. That one rule is the difference between an auto-responder and an open mail relay, and the difference is invisible while you are testing.

Full disclosure: ShipMyForm is our product, and its auto-responder is on the paid Business plan. The failure mode described below applies to every form backend, and the free do-it-yourself route at the end costs you nothing.

The shortcut, and why it is a relay

You want the person who filled in the form to get a "thanks, we got it" email. Your backend already sends you a notification, so the obvious move is to point that same mechanism at the visitor instead — put their address in the endpoint URL, or in a hidden field, and let the backend deliver there.

html
<!-- Do not do this -->
<form id="booking">
  <input name="email" />
</form>
<script>
  booking.onsubmit = async (e) => {
    e.preventDefault();
    const to = document.querySelector('[name=email]').value;
    // The PAGE is choosing who receives mail from your sender.
    await fetch(`https://example-form-backend.com/to/${encodeURIComponent(to)}`, {
      method: "POST",
      body: JSON.stringify({ _subject: "Booking confirmed", ...fields }),
    });
  };
</script>

It works immediately. Someone books, they get an email, everyone is happy.

What you have actually built is an endpoint on the public internet that sends attacker-chosen text, to an attacker-chosen address, from your sending domain. Nothing in that snippet is a secret: the URL shape, the recipient and the subject are all visible in the page and all editable by anyone with dev tools.

This is not hypothetical:

We found this pattern running on live sites — a booking page emailing each visitor their own confirmation, with the recipient taken from the form. The sites were built by people solving a real problem in the only way they could see. One of them even added copy coaching recipients through our consent prompt, because the gate was in the way of the thing they were trying to do.

What goes wrong, in order of how much it hurts

  1. Your sending reputation is shared. Mail to people who never asked for it produces spam complaints. Those complaints attach to the sending domain and IP, which means every other message from that sender — including the notifications you actually care about — starts landing in spam.
  2. It is a phishing primitive. Arbitrary subject, arbitrary body, a real sending domain with working SPF and DKIM. That is a better starting point than most phishing kits have.
  3. It is unsolicited mail under most privacy regimes. The person did not consent to hear from you, and "a website put their address in a URL" is not a lawful basis anywhere.

The rule that fixes it

The backend decides the recipient, by reading it out of the submission it just received. The page never names it.

That sounds like a small distinction and it is the whole thing. If the recipient can only be an address that was just submitted to this specific form, then the worst an attacker can do is send one email to an address they already typed — which is not an attack, it is a form submission.

Everything else in this article is the detail of making that rule hold.

The anti-abuse parts people leave out

An auto-responder is the riskiest email a form backend sends, because the address is whatever a visitor typed. Four limits are not optional, and most DIY versions have none of them:

LimitWhat it stops
One reply per address per dayA loop, or someone refreshing, turning into a mail bomb aimed at one person
A per-form daily capA bot submitting ten thousand addresses overnight
Refuse disposable and undeliverable domainsBounces, which damage sender reputation faster than complaints
Never reply to a test submissionYour own dashboard's "send test" quietly emailing a placeholder address

For reference, ShipMyForm's implementation uses one reply per address per day, 200 per form per day, refuses placeholder, disposable and previously-bounced domains before sending, and skips submissions that came from the dashboard's own test button.

Set Reply-To to yourself, not to the form:

The confirmation comes from your sending domain, but the person replying wants to reach you. Set Reply-To to the address that owns the form. Without it, replies go to a no-reply mailbox and the customer concludes you ignored them.

Doing it with ShipMyForm

Open the form, go to Settings → Auto-reply, and turn it on. Two fields:

  • Subject — e.g. We got your message, {{name}}
  • Message — the body, with the same {{field}} tokens

Tokens are replaced with that submission's values, and a token for a field the submission does not contain renders as empty rather than leaving {{name}} sitting in the text.

The recipient is never configured, which is the point. ShipMyForm finds it in the submission: first a field whose name looks like an email and whose value is one, then failing that any value that is an email address. So a form with <input name="email"> works with no mapping, and a form with <input name="contact_email"> does too.

If no address is found, nothing is sent. A form that does not collect an email address cannot be made to reply to one.

The free route: webhook into your own mail

The auto-responder is on the Business plan. On any plan, including free, you can build the same thing and own the sending yourself:

text
form → ShipMyForm → webhook → your automation → your mail provider → submitter

Add the free Webhook connector, point it at n8n, Zapier or Make, read the submitter's address from data, and send through Postmark, Resend, SES or whatever you already use.

Two things to carry across, because the automation will not do them for you:

  • Re-implement the rate limits. Your automation will happily send ten thousand emails. The table above is the minimum.
  • Verify the webhook signature. Every delivery carries an X-ShipMyForm-Signature header: sha256= followed by an HMAC-SHA256 of the raw body, keyed with the connector's signing secret. Your automation's inbound URL is public, so without checking it you have rebuilt the original problem one layer back — an open endpoint that makes you send mail.

The trade-off is reputation: you are sending from your own domain, so bounces and complaints land on you rather than on us. For a lot of people that is the right answer anyway.

What not to do, summarised

  • Do not put the recipient in the URL or in a hidden field.
  • Do not call a mail provider's API from the browser — the key is in your page.
  • Do not send a confirmation without rate limits.
  • Do not send one at all if the form does not collect an email address. A confirmation to an address you guessed is just spam with good intentions.

Next steps

Frequently asked questions

How do I email the person who filled in my form?
Use your form backend's auto-responder: it reads the email address out of the submission itself and replies to that address. What you must not do is let the page choose the recipient — for example by putting the visitor's address in the endpoint URL or in a hidden field that the backend sends to. That version works in testing and is an open relay in production, because anyone who reads your page source can then send mail to any address they like through your sender.
Why can't I just send the confirmation from JavaScript?
Because a browser cannot send email, so any client-side version needs a mail provider's API key in the page — which publishes that key to every visitor. Someone can then send mail as you, to anyone, until you rotate it. The confirmation has to be sent by something the visitor cannot read or control, which means a server.
Will confirmation emails land in spam?
They are more likely to than your own notifications, because the recipient never opted in — they filled in a form and received mail from a domain they do not recognise. Keep the message short, make the sending domain recognisable, set a Reply-To the person can actually reply to, and never send to an address you have not just received a submission from. A confirmation that nobody asked for is indistinguishable from spam to a filter.
Does ShipMyForm send confirmation emails on the free plan?
No. The auto-responder is on the Business plan. On any plan you can build the same thing by routing the free webhook connector into an automation that sends from your own mail provider, which is covered in this guide — you own the sending reputation in that case, which is the main trade-off.
What stops a bot from using my confirmation email to spam people?
Rate limits, and they are not optional. A correct implementation replies at most once per address per day, caps replies per form per day, refuses disposable and undeliverable domains, and never replies to a test submission. Without those, a bot can submit a thousand addresses and your form becomes a bounce generator pointed at your own sending reputation.

Related guides