Skip to main content

Troubleshooting

WordPress Form Not Sending Email? Work Through This List

WordPress contact form not sending email? Check the saved submission, From and Reply-To headers, email log and authenticated delivery service in order.

When a WordPress form isn’t sending email, a visitor’s request can go unanswered even when the page shows success. You should first establish whether the submission was saved, then trace the notification through its email log and delivery service. That separates a failed submit from a saved request whose email didn’t arrive.

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.

Illustration of an email failing to leave a WordPress site 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.

In Core Forms, you can look for the test entry in the submissions inbox when saving submissions is enabled. A saved entry and an email action are separate outcomes. If storage is disabled, an absent entry doesn’t prove the form failed.

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 can send through a service such as Emailit. You can use its response and delivery events to distinguish an accepted request from a bounce or a message delivered later. An API isn’t automatically faster than SMTP, and acceptance doesn’t prove inbox delivery.

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 provider’s setup instructions give you the DNS records to publish. Gmail’s sender guidelines distinguish ordinary senders from bulk senders: all senders need SPF or DKIM, while bulk senders have stronger authentication requirements. I would configure both SPF and DKIM for the provider and check its DMARC guidance rather than assume a successful transport test guarantees delivery.

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.

A Saved Request With a Failed Email

You can make a useful test entry with a unique subject, such as Delivery check 42. Then compare the records:

  • Submission saved: the form accepted and stored the request.
  • Email action failed: the delivery provider or transport didn’t accept the notification.
  • Email action accepted but no inbox message: inspect the provider’s delivery or bounce events and the recipient’s filtering.

I would fix the failing layer before asking the visitor to submit again. Retrying the email is different from recreating the submission, and duplicate requests can make support harder.

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.

Build the form. Stop reading.

Every note here came out of a real Core Forms setup.