Troubleshooting
WordPress Form Not Sending Email? Work Through This List
Nine times out of ten your form works fine — the email dies at delivery. Here's the checklist I run on client sites, in the order that finds it fastest.
A WordPress form not sending email is almost never a form problem. Nine times out of ten the form submitted fine and the notification died at delivery — because WordPress sends mail through PHP’s mail() function with no authentication, and unauthenticated mail gets junked or silently dropped.
The fix is routing mail through an authenticated service: an SMTP plugin or an email API.
That’s the answer. The rest of this post is the order I check things in on client sites, because “install an SMTP plugin” fixes most cases but not all of them, and guessing wastes an afternoon.
The form did its job. The email never made it out of the building.
First, prove the form actually submitted
Before touching a single email setting, confirm the submission exists. If the entry is in the database, you have a delivery problem, not a form problem — and that changes everything you do next.
Open your form plugin’s submissions screen and look for the test entry. In Core Forms that’s the submissions inbox; every submission lands there whether or not any email went out.
Entry exists, no email: delivery problem. Skip ahead to the SMTP section.
No entry at all: now it’s actually a contact form not working in WordPress. Check for a JavaScript error in the browser console, a security plugin blocking the AJAX request, or a caching plugin serving a stale nonce. These are the usual three.
If your plugin stores nothing (more on Contact Form 7 below), submit a test with a unique word in the message, then search your mail server logs or database for it. No storage means you’re debugging blind — I’ve written about why I log every submission for exactly this reason.
Check spam and the From address
The most common non-fix I see: the email is arriving, in the spam folder, and nobody looked. Search spam for the site’s domain name before changing anything.
If it’s in spam, the usual culprit is the From address. Here’s the rule:
From must be an address at your domain. Not the visitor’s email. When your form sends “from” visitor@gmail.com but the mail actually comes from your server, Gmail sees a forged sender and junks it. That’s not a bug — that’s spam filtering doing its job.
The visitor’s email goes in Reply-To. You still hit reply and reach them. The envelope just stops lying about who sent it.
So: From is forms@yourdomain.com, Reply-To is the visitor. Every form plugin supports this; most default configurations get it wrong. I covered the full spam-folder rabbit hole in why form emails land in spam.
Route mail through an authenticated service
If the submission exists and the From address is right but email still isn’t arriving, stop patching and fix the transport. WordPress’s default mail() sends from your web server’s IP with no credentials — receiving servers have no way to verify it, and shared-hosting IPs usually carry a bad reputation you inherited from a neighbor.
Two ways out:
An SMTP plugin. Routes WordPress’s wp_mail() function through a real mailbox — Google Workspace, Microsoft 365, your host’s mail service. Install, add credentials, send a test. Fifteen minutes.
An email API. Services like Emailit, Resend, or Postmark send over HTTPS with an API key. Faster than SMTP, and you get delivery status back instead of a shrug.
Either way, two DNS records make it stick:
SPF is a DNS entry listing which servers are allowed to send mail for your domain.
DKIM is a cryptographic signature proving the email wasn’t tampered with in transit.
Your email service’s setup docs give you both records to paste into DNS, and Gmail’s sender guidelines now expect both from anyone sending to Gmail addresses. Ten minutes, and it’s the difference between “usually arrives” and “arrives.”
Read the email log
Once mail is routed through a real service, stop guessing and read the log. An email log answers the three questions that actually matter:
Was the send attempted? If there’s no log entry, WordPress never tried — the problem is in the form’s notification settings, not delivery.
Was it accepted? The receiving server said yes. If it’s still missing, you’re back to the spam folder or a mailbox rule.
Did it bounce? The log shows the rejection reason — bad recipient address, blocked IP, missing SPF. The error message tells you the fix instead of making you guess it.
Without a log, every one of these looks identical: “the email didn’t arrive.” With one, most WordPress form not sending email tickets take five minutes.
Contact Form 7 notes
Contact Form 7 not sending email is the highest-stakes version of this problem, because CF7 stores nothing by default. No submissions table, no log. If the email fails, the lead is gone — not delayed, gone. If you’re staying on CF7, install Flamingo so submissions survive; if you’re not, storage is a good reason to switch.
Two CF7-specific gotchas:
Mail (2) is a separate email. CF7’s second mail template — usually the visitor’s auto-reply — has its own From, its own recipient, its own failure modes. Sites regularly fix Mail and forget Mail (2), then wonder why visitors say they never got a confirmation.
Additional Headers is where From lies live. The classic broken CF7 setup puts [your-email] in the From field or in a From: line under Additional Headers. That’s the forged-sender problem from earlier. Move the visitor to Reply-To: [your-email] and set From to your domain.
When it’s the host
Some hosts disable PHP’s mail() function outright — common on hardened managed hosting and some budget shared plans. Every plugin’s email will fail identically, and no amount of form-side configuration fixes it.
Test with a plain wp_mail() call, bypassing your form plugin entirely:
wp_mail( 'you@example.com', 'Test from ' . home_url(), 'If this arrives, mail() works.' );
Drop that in a WP-CLI eval or a temporary mu-plugin. If nothing arrives, the server can’t send mail at all — and an email API over HTTPS sidesteps the whole thing, since it never touches mail() or port 25.
If the test arrives fine but your form emails don’t, the host is off the hook and you’re back to the From-address and plugin-settings checks above.
FAQ
Why does my WordPress form say “sent” but no email arrives?
Because “sent” means WordPress handed the message to PHP’s mail() function and mail() didn’t error. It says nothing about delivery. The message can be accepted locally and then dropped or junked downstream. An email log or an authenticated email service gives you real delivery status.
Should the From address be my email or the visitor’s?
Yours — always an address at your own domain. Putting the visitor’s address in From makes the email look forged, and Gmail and Outlook filter it accordingly. Put the visitor’s address in Reply-To instead; replying still reaches them directly, and delivery stops failing.
Do I need both SPF and DKIM?
Yes, set up both. SPF lists which servers may send for your domain; DKIM signs each message so it can’t be altered in transit. Modern inbox providers effectively expect both, and your email service’s docs hand you the exact DNS records. It’s a one-time, ten-minute job.
Is Contact Form 7 not sending email a CF7 bug?
Usually not. CF7 hands mail to wp_mail() like every other plugin, so it fails wherever unauthenticated WordPress mail fails. CF7’s real risk is that it stores no submissions by default — a failed email means a lost lead. Add storage or an SMTP/API service before assuming the plugin is broken.
My host says email works. Why do form emails still fail?
“Works” from the host means mail() executes. The message can still be rejected downstream for a forged From address, missing SPF/DKIM, or the server IP’s poor reputation. Route form mail through an authenticated SMTP or API service and the host’s mail stack stops mattering.