splitforms.com
All articles/ TUTORIALS7 MIN READPublished May 1, 2026

How to receive form submissions by email (the modern way)

Routing form data to your inbox without PHP, mailto links, or custom servers. The 2026 stack for HTML form submissions delivered as email.

✶ Written by
splitforms.com / blog

Founder of splitforms — the form backend API for developers. Writes about form UX, anti-spam, and shipping web apps without backend code.

Why "form to email" is harder than it looks

On paper, getting a contact form into your inbox is a one-liner. In practice, modern email is a hostile environment built to reject anything that smells weird. Your shiny new contact form has to navigate:

  • SPF, DKIM, and increasingly DMARC checks at the receiving server
  • Reputation scoring on the sending IP and domain
  • Content scoring (links, attachments, suspicious phrasing)
  • Greylisting, throttling, and silent drops by Gmail and Outlook
  • Your own "Updates" or "Promotions" tab black holes

Skip any of these and your form will look like it's working — 200 OK on the request — while every submission silently lands in spam. The cost: lost leads you'll never know about. This is why we built splitforms in the first place: every other backend we tried treated deliverability as someone else's problem.

The 3 modern stacks that actually work

Forget PHP mail(). Forget unsigned SMTP from your VPS. Three patterns reliably deliver form submissions to a real inbox in 2026:

  1. Hosted form backend— splitforms, Formspree, Web3Forms, Basin. Drop a URL in your form's action.
  2. Serverless function + transactional email API — Vercel/Netlify/Workers calling Postmark, Resend, SendGrid, or Mailgun.
  3. Self-hosted forwarder — n8n, FormBricks, or a Docker container running on your own infra, sending through a paid SMTP relay.

Stack 1: Hosted form backend

The lowest-effort option. A form backend is a single POST endpoint that receives multipart form data, applies spam filtering, and emails the contents. With splitforms, the entire integration is one HTML file:

<form action="https://splitforms.com/api/submit" method="POST">
  <input type="hidden" name="access_key" value="YOUR_ACCESS_KEY" />
  <input type="hidden" name="subject" value="New contact form submission" />
  <input type="hidden" name="from_name" value="yoursite.com" />

  <input name="name" placeholder="Name" required />
  <input name="email" type="email" placeholder="Email" required />
  <textarea name="message" placeholder="What's up?" required></textarea>

  <!-- honeypot -->
  <input name="botcheck" type="checkbox" style="display:none" tabindex="-1" />

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

splitforms emails you the submission within ~2 seconds, sets Reply-To to the visitor's submitted email so you can reply directly, runs spam scoring before delivery, and keeps a copy in your dashboard so you don't lose data when an email bounces.

Pricing reality check: most hosted backends (including splitforms) have a free tier. We give 1,000 submissions/month forever; Formspree gives 50, Netlify Forms gives 100. Pick based on volume, not loyalty.

Stack 2: Serverless function + transactional API

You want full control or already have a Postmark/Resend account. Write a tiny function, ship submissions yourself.

Vercel Route Handler with Resend:

// app/api/contact/route.ts
import { Resend } from 'resend';

const resend = new Resend(process.env.RESEND_API_KEY);

export async function POST(req: Request) {
  const data = await req.formData();

  // honeypot
  if (data.get('botcheck')) {
    return new Response('OK', { status: 200 });
  }

  const name = String(data.get('name') ?? '');
  const email = String(data.get('email') ?? '');
  const message = String(data.get('message') ?? '');

  const { error } = await resend.emails.send({
    from: 'forms@yourdomain.com',
    to: 'you@yourdomain.com',
    replyTo: email,
    subject: `New contact form: ${name}`,
    text: `From: ${name} <${email}>\n\n${message}`,
  });

  if (error) {
    return new Response('Mail send failed', { status: 500 });
  }

  return Response.redirect(new URL('/thanks', req.url), 303);
}

You'll need to verify yourdomain.com in Resend by adding their SPF and DKIM CNAME records. Until those propagate, everything you send will land in spam.

Stack 3: Self-hosted forwarder + your own SMTP

Honest tradeoff: you save money at scale and own all the data. You also own deliverability, retries, queueing, monitoring, and the 3am pages when your VPS's IP gets blocked by Microsoft.

A minimal Node forwarder using nodemailer + Postmark SMTP:

import express from 'express';
import nodemailer from 'nodemailer';

const app = express();
app.use(express.urlencoded({ extended: true }));

const transport = nodemailer.createTransport({
  host: 'smtp.postmarkapp.com',
  port: 587,
  auth: {
    user: process.env.POSTMARK_TOKEN,
    pass: process.env.POSTMARK_TOKEN,
  },
});

app.post('/contact', async (req, res) => {
  if (req.body.botcheck) return res.status(200).send('OK');

  await transport.sendMail({
    from: 'forms@yourdomain.com',
    to: 'you@yourdomain.com',
    replyTo: req.body.email,
    subject: `Contact: ${req.body.name}`,
    text: req.body.message,
  });

  res.redirect(303, '/thanks');
});

app.listen(3000);

For most teams, the operational overhead beats the cost savings before you hit 10,000 submissions/month. After that, math starts flipping. We're honest about it: at very high volume, self-hosting plus a SendGrid contract is cheaper than splitforms.

SPF, DKIM, DMARC: the deliverability checklist

Three DNS records turn a contact form from "sometimes works" into "reliably hits the inbox":

RecordWhat it doesWhere to set it
SPF (TXT)Lists IPs allowed to send for your domainYour DNS provider, copied from your email service
DKIM (TXT or CNAME)Cryptographically signs outgoing mailYour DNS, generated by your email service
DMARC (TXT)Tells receivers what to do if SPF/DKIM failYour DNS, start with p=none for monitoring

splitforms sends from a verified sending domain we control, so you don't need to add any DNS records to start receiving mail. For deliverability-sensitive teams (sales, recruiting), connect your own domain in the dashboard and add the records once.

Setting Reply-To so you can actually reply

The most common form-to-email mistake: you receive a submission from forms@formbackend.com, hit reply, and email the form provider instead of the lead. Always set the Reply-Toheader to the visitor's submitted email address.

splitforms does this automatically when your form has a field named email. In serverless code, set replyTo explicitly when calling your email API, as shown in the Resend example above.

5 mistakes that send your forms to spam

  1. Sending from gmail.com or yahoo.com via SMTP relay. DMARC alignment fails; mail lands in spam or bounces. Use a domain you own.
  2. No SPF or DKIM record on the sending domain. Gmail will quietly drop these into spam.
  3. Putting the visitor's email in the From header. That's spoofing — DMARC will catch it. Put it in Reply-To instead.
  4. Including too many links in the email body. Spam scoring penalizes any email with 3+ outbound links.
  5. Sending HTML-only emails with no plain-text part. Plain-text fallback is a small but real spam-score win.

Tech support and troubleshooting

Five issues that account for almost every form-to-email outage:

  • Mail lands in spam after working for weeks — domain reputation slipped or DKIM record was rotated. Re-verify SPF/DKIM and run a fresh mail-tester.com check.
  • Reply hits the form provider, not the lead — Reply-To header isn't being set. Confirm your form has an email field and the backend is configured to use it.
  • Submission returns 200 but no email arrives — message was scored as spam and silently dropped. Check the splitforms dashboard; resubmit after lowering spam threshold or whitelisting the IP.
  • Bounces from your own domain — DMARC alignment failure when sending as user@yourdomain. Send as forms@yourdomain instead and put the visitor email in Reply-To.
  • Latency over 10 seconds — shared SMTP host throttling or DNS lookup stall. Switch to a transactional provider (Postmark, Resend) or let splitforms handle delivery.

The full delivery pipeline, retry policy, and signature spec are in the splitforms docs and API reference; account questions live in the splitforms FAQ.

Frequently asked questions

What is the easiest way to receive HTML form submissions by email?

Use a hosted form backend like splitforms (https://splitforms.com/api/submit). Point your form's action attribute at the endpoint, include a hidden access_key input, and submissions arrive in your inbox immediately. No SMTP server, no DNS records, no PHP required.

Why does mailto: not work for contact forms?

mailto: opens the visitor's local email client, which mobile users on Gmail, anyone on a shared computer, or most corporate users won't have set up. Industry conversion data shows mailto links convert 3-10x worse than a real form. They also bypass any spam filtering or analytics.

Why are my form emails landing in spam?

Almost always a deliverability issue: missing SPF or DKIM records on the sending domain, sending from an unverified address, or using shared SMTP IPs with bad reputation. Use a dedicated transactional email service (Postmark, Resend, SendGrid) and authenticate your domain. splitforms handles this for you out of the box.

Can I receive form submissions to multiple email addresses?

Yes. splitforms supports CC and BCC recipients on Pro plans. You can also use a Google Group or shared inbox as the destination address. For per-form routing, create separate access keys per form, each pointed at a different recipient.

How fast do form-to-email submissions arrive?

With a modern transactional provider, end-to-end latency from form submit to inbox is typically 200ms-3 seconds. PHP mail() via shared hosting can take 30+ seconds or never arrive at all. splitforms ships emails through Postmark and averages under 2 seconds inbox time.

Next steps

About the author
✻ ✻ ✻

Get your free contact form API key in 60 seconds.

1,000 free form submissions per month. No credit card. No SDK, no PHP, no plugin. Drop one POST endpoint in your form and submissions land in your inbox.

Generate access key →Read the docs
v0.1 · founders pricing locked in · early access open