wp_mail(), which by default uses your host's unauthenticated PHP mail() — and that last hop is where WordPress emails die. Confirm the notification is on and routed correctly, then work through the nine fixes in order: from an SMTP plugin and SPF/DKIM/DMARC records to a plugin-free form endpoint that stores every entry.Point any HTML form at one endpoint. 500 free submissions — no card, no time limit — and unlimited forms.
Create free accountThe root cause: wp_mail() and unauthenticated PHP mail
When a visitor submits any WordPress contact form — Contact Form 7, WPForms, Gravity Forms, Elementor, Ninja Forms — the plugin validates the fields, saves the entry, and then asks WordPress to send the notification. WordPress routes that through wp_mail(), which by default calls the server's PHP mail() function. That last hop is where the email dies:
- Many shared hosts disable or throttle outbound PHP mail to fight spam abuse, so the message never leaves the server.
- The message is sent unauthenticated — no SPF/DKIM alignment — from an IP shared with other sites, so Gmail and Outlook spam-folder it by default.
- Failures are silent: the plugin logs the notification as sent because wp_mail() accepted it, but no bounce or error reaches wp-admin.
This is the same plumbing behind every "form works but no email arrives" report, and it hits every plugin identically. The entry itself is almost always saved, so the lead is not gone; only the notification email is. The nine fixes below are ordered from the quickest setting check to the permanent fix that removes wp_mail from the path entirely.
Nine fixes, in order
1. The host blocks or limits PHP mail() / wp_mail
Before touching any plugin, prove where the mail stops. Install a plugin-free check such as WP Mail Logging, or run the email test in WordPress → Tools → Site Health, and send a test message. If the log shows the message was handed to PHP mail() but nothing arrives, your host is blocking or throttling outbound mail — the most common cause on shared hosting. Some hosts cap the number of messages per hour, so a form that works in the morning can silently fail after a burst of submissions. Confirm the failure is at the mail layer, not the form, before moving on.
2. No SMTP: set up an SMTP plugin with your mail provider
The standard fix is to stop using the host's PHP mail and send through an authenticated SMTP account. Install WP Mail SMTP, FluentSMTP or Post SMTP and connect a real mail provider — Google Workspace, Brevo, Mailgun or Amazon SES. Now wp_mail(), and therefore every form plugin's notification, sends through an account with proper SPF/DKIM instead of the server's unauthenticated PHP mail, and notifications start landing in the inbox. Use the plugin's built-in test-email tool afterwards to confirm delivery. Cost: a plugin to maintain plus SMTP credentials to keep secure.
3. The From address doesn't match the domain, so mail fails SPF/DMARC
In the form plugin's notification settings, set the From Email to an address on a domain you control — for example forms@yourdomain.com — instead of a default like wordpress@yourdomain.com or a no-reply address on a different domain. If the From domain is not the one your DNS authorizes for sending, the message fails SPF and DMARC alignment and gets filtered. Put the visitor's address in Reply-To so replies still reach the person who filled in the form. This is necessary, but on shared hosting it is rarely sufficient by itself — pair it with fix 2.
4. SPF, DKIM and DMARC records are missing
Even authenticated mail can be spam-folded if your DNS does not say your sender is allowed to send for your domain. Add an SPF record covering your mail provider, enable DKIM signing at the provider and publish the keys in DNS, and add a DMARC policy (start with p=none and monitor before tightening). Check each record with the free SPF checker, DKIM checker and DMARC checker. A missing or misconfigured record here is a frequent reason mail that "was sent" never reaches the inbox.
5. Emails land in spam
If the message is delivered but sits in the junk folder, the cause is deliverability, not the form. Unauthenticated, shared-IP mail from a From address that fails DMARC is exactly what mailbox providers filter. Send through an authenticated provider (fix 2), set the From Email to your own domain (fix 3), and publish SPF, DKIM and DMARC (fix 4). Ask the recipient to add the sender to their contacts and mark the message as not spam so the provider trusts it going forward. The full breakdown of why notification mail gets filtered is in why contact form emails go to spam.
6. A wrong recipient address in the plugin's notification settings
Open the form's notification settings in the plugin and confirm the Send To address is the inbox you actually read. It is often an old address, a departed employee's mailbox, or a shared inbox nobody monitors. Watch for a stray comma or space that creates a malformed recipient, and for a default tag like {admin_email} that points at the wrong address. Check any conditional logic on the notification — a rule that does not match the submission means the notification simply never fires. Fix the address and resubmit a test form.
7. A caching or security plugin blocks the AJAX submit
If the form sometimes submits and sometimes does not — or the entry is created but the notification never fires — a caching plugin serving stale HTML or a security plugin blocking the AJAX request can be the cause. A cached page can serve an expired nonce, so the submit is rejected as a security check. Temporarily disable page caching and security/anti-spam plugins, resubmit the form, and confirm the notification fires. If it does, re-enable them one at a time and allowlist the form's AJAX endpoint so the nonce is always fresh.
8. A plugin or theme conflict
If nothing above is the cause, test for a conflict. Switch to a default theme (such as Twenty Twenty-Four) and deactivate all plugins except the form plugin, then resubmit. If the email arrives, reactivate plugins one at a time until the failure returns — that plugin is the culprit, and you can then look for a setting or a compatibility update. A theme that overrides the form's markup or enqueues a script that intercepts the submit can break it the same way. This isolates a third-party cause you would otherwise chase forever.
9. Skip wp_mail entirely: point the form at a hosted form backend
If you would rather not depend on wp_mail at all, take WordPress out of the submission path and point a plain HTML form at a hosted endpoint. With splitforms, the form POSTs to https://splitforms.com/api/submit with a hidden access key:
<form action="https://splitforms.com/api/submit" method="POST">
<input type="hidden" name="access_key" value="YOUR_ACCESS_KEY" />
<input name="name" type="text" placeholder="Name" required />
<input name="email" type="email" placeholder="Email" required />
<textarea name="message" placeholder="Message" required></textarea>
<button type="submit">Send</button>
</form>Every accepted entry is stored in a searchable dashboard before the owner notification email is attempted, so a mail failure can never lose a lead. Spam is filtered by automatic spam scoring plus a honeypot, and notifications are sent from deliverability-managed infrastructure with SPF, DKIM and DMARC handled for you. Because the form posts straight to the backend, it does not depend on your host's PHP mail, a caching plugin, or a plugin conflict. See adding a contact form to WordPress without a plugin and the free contact form page for the full walkthrough.
Plugin-specific guides
The fixes above apply to every WordPress form plugin. If you want the settings walked through for the exact plugin you use, start with the guide for it:
- Contact Form 7 not sending emails — notification and mailer settings for CF7.
- Elementor form not sending email — Elementor Forms notifications and the email leg.
- Gravity Forms not sending email — Gravity Forms notification and confirmation settings.
- WPForms not sending email — WPForms notifications, email logs and smart tags.
- Ninja Forms not sending email — Ninja Forms notification and SMTP settings.
Other form problems and fixes
- Contact form not working
- HTML form not submitting
- Form submission canceled (form not connected)
- 405 Method Not Allowed
- 401 Unauthorized
- CORS error
- Form sends but no email arrives
- Emails land in spam
- Elementor form not sending
- Gravity Forms not sending
- WPForms not sending
- Ninja Forms not sending
- mailto: action not working
- Works in preview but not live
- Netlify form not working
- Webflow form not working
- Wix form not working
- Framer form not working
- Required attribute not working
- input type=number maxlength not working
- autocomplete="off" not working
- Form resubmission on refresh
- Duplicate form submissions
Still stuck? Test your endpoint with our free Form Action Tester or contact splitforms support.
FAQ
Why is my WordPress contact form not sending email?
Almost always because the email leg fails, not the form. Every WordPress form plugin hands the message to wp_mail(), which by default calls your host's unauthenticated PHP mail(). Shared hosts often block or throttle that mail, and receiving servers spam-folder it because it has no SPF/DKIM alignment. The submission is usually still saved in the plugin, so the lead is not gone — only the notification email is. Work through the nine fixes in order, starting with confirming the notification is on and routed to the right address.
Does WordPress need an SMTP plugin to send form email?
Not strictly, but on most shared hosts it is the reliable fix. WordPress sends through wp_mail(), so installing an SMTP plugin such as WP Mail SMTP, FluentSMTP or Post SMTP and connecting a real mail provider (Google Workspace, Brevo, Mailgun, Amazon SES) gives the message proper SPF/DKIM authentication instead of the server's unauthenticated PHP mail. You then own the SMTP credentials and the provider's deliverability settings, and notifications start landing in the inbox.
Why do my WordPress form emails go to spam?
Because they leave your web server through PHP mail() with no SPF/DKIM alignment, often from an IP shared with many other sites, and often with a From address that fails DMARC. Mailbox providers treat that unauthenticated, shared-IP mail as suspicious by default. Send through an authenticated provider with an SMTP plugin, set the From Email to an address on your own domain, and publish SPF, DKIM and DMARC records for that domain. The full breakdown is in the guide to why contact form emails go to spam.
Can I send WordPress form email without wp_mail at all?
Yes — bypass WordPress mail entirely and point a plain HTML form at an external form endpoint. With splitforms, the form POSTs to https://splitforms.com/api/submit with a hidden access key, every accepted entry is stored in a searchable dashboard before the owner notification email is attempted, spam is filtered by automatic spam scoring plus a honeypot, and delivery runs on managed infrastructure with SPF, DKIM and DMARC handled for you. The saved dashboard record remains available if email fails, so a bad mail day never loses a lead.
Stop depending on wp_mail — point your form at https://splitforms.com/api/submit and every lead is stored, filtered, and emailed. Get a free access key.
Related: why contact form emails go to spam, contact form works but no email, and the free contact form.