Skip to content
FormSubmit
Email Deliverability

Contact Form Not Sending Email? A Troubleshooting Checklist

Contact form not sending email? Work through this checklist: broken submits, missing name attributes, PHP mail() limits, SPF/DKIM, spam folders and wp_mail.

FormSubmit Team

7 min read

A contact form with a checklist of failure points between the submit button and the inbox

When a contact form is not sending email, the problem is in one of three places: the submission never reaches your server, your server can't send mail, or the email is sent and then filtered before it reaches your inbox. Testing each stage in order, from browser to server to inbox, tells you which one it is, usually in under half an hour.

Here's the full checklist, with a test and a fix for each step. Start at the top. There's no point debugging SPF records if the form never submits.

Stage 1: Does the form actually submit?

Missing or wrong name attributes

Browsers only send fields that have a name. An input with only an id is silently left out, so the handler receives an empty message, or rejects it as incomplete.

html
<!-- Wrong: never submitted -->
<input type="email" id="email">

<!-- Right -->
<input type="email" id="email" name="email">

Test: open DevTools → Network, submit the form and click the request. Check the payload lists every field with a value.

Fix: give every input, select and textarea a name. The handler expects specific names, so match them exactly. email and Email are different fields.

Wrong action or method

If action points at a file that doesn't exist, you'll see a 404. If method is missing, the browser sends a GET with the data in the URL, and most mail handlers ignore it.

Test: check the request URL and status code in the Network tab. A 404, 405 or 500 tells you the problem is on the server side of the request, not email.

Fix: use method="POST" and an action that resolves to your handler. Our guide to the HTML form action attribute explains how action, method and enctype fit together.

JavaScript errors and preventDefault

Many forms submit with fetch and call event.preventDefault(). If the script throws before the request is sent, the page shows nothing, or a thank-you message, and no request goes out.

Test: open the Console tab and submit. Any red error before the request means the script is the problem. Also check the Network tab: no request at all means the data never left the browser.

Fix: fix the error, and only show a success message after the response comes back OK. Our guide to submitting a form with JavaScript shows a pattern that handles errors properly.

A mailto: action

action="mailto:you@example.com" doesn't send email. It asks the visitor's computer to open a mail app, which many people don't have configured. If that's your setup, nothing is broken. It just never worked reliably.

Stage 2: Can the server send mail?

If the request reaches your server and returns a success status, the next question is whether the server can send email at all.

PHP mail() disabled or restricted

Many PHP contact forms rely on mail(). Plenty of hosts disable it, rate-limit it or only allow it from specific addresses, because it's widely abused for spam.

Test: upload a minimal script and load it in the browser:

php
<?php
$ok = mail('you@yourdomain.com', 'mail() test', 'If you can read this, mail() works.', 'From: website@yourdomain.com');
var_dump($ok);

bool(false) means PHP couldn't hand the message to the local mail program. bool(true) only means the handoff worked, not that the email was delivered. Delete the script when you're done.

Fix: check your host's documentation or support. Often the answer is to stop using mail() and send through an authenticated SMTP account instead. A library like PHPMailer makes that straightforward. If you'd rather avoid server-side code completely, see how to build a contact form without PHP.

Blocked SMTP ports

Cloud servers and some hosts block outbound port 25, and sometimes 465 and 587 too, to stop spam. Your SMTP connection then times out.

Test: check your application's error log for connection timeouts, or run nc -vz smtp.your-provider.com 587 from the server.

Fix: use the port your provider recommends (usually 587 with STARTTLS), ask your host to open it, or use a provider that offers an HTTP sending API.

WordPress wp_mail

WordPress sends every email, including contact form plugin notifications, through wp_mail, which uses PHP mail() unless something overrides it. So a WordPress contact form that doesn't send email usually has a server mail problem, not a plugin problem.

Test: reset your password from the login page. If that email doesn't arrive either, the problem is site-wide. Many SMTP plugins also include a "send test email" tool and an email log.

Fix: install an SMTP plugin and connect it to an authenticated email provider. Then check the plugin's form settings: a wrong "To" address, or a "From" address set to the visitor's email, is common.

Stage 3: Is the email being sent but filtered?

If the server says the email was sent but nothing shows up, the message is being filtered or rejected on the way to you.

Check spam, quarantine and filters

Look in spam, junk, the Promotions tab and any admin quarantine (Microsoft 365 and Google Workspace both have one). Check for inbox rules or forwarding that moves messages out of sight.

Fix: mark the message as "Not spam", add the sender to your contacts and create a filter that always delivers it.

The From address spoofs the visitor

Scripts that set From: to whatever the visitor typed make your server claim to be Gmail, Outlook or someone's company domain. Receiving servers check whether your server is allowed to send for that domain. It isn't, so the message is filtered or rejected.

Fix: send from a fixed address on your own domain and put the visitor in Reply-To:

text
From: Website <forms@yourdomain.com>
Reply-To: jane@example.com

Missing SPF, DKIM or DMARC

Even with the right From address, mail from a server your DNS doesn't authorize fails authentication. Major mailbox providers expect authenticated senders and filter, or reject, mail that isn't.

Test: open a notification that did arrive (or one in spam) and view the raw headers. In Gmail, that's "Show original". Look at the SPF, DKIM and DMARC results. Online DNS lookup tools will also show which records you've published.

Fix: publish one SPF record that includes your sending service, enable DKIM signing with your provider, and add a DMARC record starting at p=none. Our post on contact form emails going to spam covers these records step by step.

Rate limits and provider blocks

Hosts often cap outgoing mail per hour. A burst of bot submissions can use up that cap, or get your shared IP listed on a blocklist, so real messages stop going out. Corporate mail gateways may also reject mail from IPs with a poor reputation.

Test: check the host's mail logs or your email provider's activity log for "deferred", "rate limited" or "rejected" entries. Look up your server's IP on a public blocklist checker.

Fix: stop the spam at the form with a honeypot or captcha (see how to stop form spam), move sending to a transactional email provider, and ask your host to request delisting if your IP is on a blocklist.

The checklist at a glance

SymptomLikely causeFirst test
No request in the Network tabJavaScript error, mailto: actionConsole errors
Request sent, fields emptyMissing name attributesRequest payload
404 / 405 / 500 responseWrong action or method, handler errorStatus code, server error log
mail() returns falsePHP mail disabledMinimal test script
SMTP timeoutsBlocked portsError log, nc to port 587
Sent but never arrivesSpoofed From, no SPF/DKIMRaw headers
Worked, then stoppedRate limit or blocklist after spamMail logs, blocklist lookup

How a form backend avoids most of this

Almost every item in stages 2 and 3 comes from running your own mail sending: mail() settings, SMTP ports, DNS records and IP reputation. A hosted form backend removes that layer. The form posts to an endpoint, and the backend stores the submission and sends the notification from a sending domain it authenticates and maintains.

With FormSubmit, the change is the form's action:

html
<form action="https://formsubmit.app/f/YOUR_FORM_ID" method="POST">
  <input type="text" name="name" required>
  <input type="email" name="email" required>
  <textarea name="message" required></textarea>
  <input type="text" name="_gotcha" style="display:none" tabindex="-1" autocomplete="off">
  <button type="submit">Send</button>
</form>

What that changes in practice:

  • Notifications come from notifications@formsubmit.app, with Reply-To set to the visitor, so you can reply directly and nothing claims to be the visitor's domain.
  • Every submission is stored in the dashboard, so even if an email is filtered, the message isn't lost.
  • Spam is filtered before emails go out, with a honeypot, timing checks, content heuristics and rate limiting, so bots don't burn through sending limits.
  • No PHP, SMTP or DNS work on your host. It works on static hosting, site builders and WordPress alike.

Stage 1 still applies: fields need name attributes and JavaScript has to send the request. But that's quick to check. To set it up from scratch, follow our guide to sending an HTML form to email, or build one in the form generator. The free plan includes one form and 50 submissions a month. Add notifications@formsubmit.app to your contacts on day one.

Frequently asked questions

Why is my contact form not sending email?

Either the submission never reaches the server (a broken form, missing name attributes or a JavaScript error), the server can't send mail (PHP mail() disabled or blocked ports), or the email is sent but filtered because it fails SPF, DKIM or DMARC. Test each stage in that order.

How do I know if PHP mail() works on my host?

Upload a tiny script that calls mail() to your own address and prints the return value. A false return means PHP couldn't hand the message to a mail program. A true return only means it was handed off, so check your spam folder and the host's mail logs too.

Why does my WordPress contact form not send email?

WordPress sends with wp_mail, which uses PHP mail() by default. Many hosts restrict or disable it, and messages that do go out often fail authentication. An SMTP plugin connected to an authenticated email provider fixes most cases.

Can I use the visitor's email address as the From address?

No. Your server isn't authorized to send mail for the visitor's domain, so receivers treat it as spoofing. Send from an address on your own domain and put the visitor's email in Reply-To.

How do I fix a contact form without touching mail servers?

Post the form to a hosted form backend. It receives the submission, stores it and sends the notification from an authenticated sending domain, so PHP mail and DNS records on your host stop mattering.

Related resources

Keep reading

Your form backend is 60 seconds away

Sign up with Google or email, create a form, paste the endpoint. Free forever for small sites — no credit card.