WordPress contact form not sending email
“It has been sent.”
It hasn’t arrived.
A WordPress contact form usually stops sending email because WordPress hands each message to your web server’s PHP mail() function, often with a From address that isn’t on your domain, so the receiving server can’t verify it and rejects it or files it as spam. Fix it in this order: confirm the entry and the To address, put an address on your own domain in From and the visitor in Reply-To, publish SPF, DKIM and DMARC, then send through an SMTP provider. Below: where the message dies, a diagnoser that ranks the cause from your answers and headers, and the exact settings in Contact Form 7 and WPForms.
By the Builderify team
Why is my WordPress contact form
not sending email?
Because a form message passes through five hands before it reaches you, and the thank-you message only reports on the second. Every form plugin, from Contact Form 7 (10+ million active installs) to WPForms (5+ million), ends by calling the same WordPress function, wp_mail(). What happens after that is up to your server and the receiver.
-
01
The form
Builds the message and its headers
- To
- Contact Form 7 sends to
[_site_admin_email]and WPForms to{admin_email}unless you change it: the address in Settings › General, often years old. - Never sent
- A JavaScript error, a cached page or a spam check stops the submission. Contact Form 7 shows the same error for a mail failure and for spam.
-
02
wp_mail()
WordPress hands it to PHPMailer
- From
- With no From set, WordPress uses
wordpress@plus your site’s host. Forms that put the visitor’s address there break the next three steps. - Hooks
- Any plugin can rewrite the mailer through
phpmailer_init. Two SMTP plugins means the last one wins.
-
03
Your server
PHP mail(), unless a plugin says otherwise
- Limits
- WordPress’s default is PHP’s
mail(). Hosts cap it, route it through their own service, or block port 25 outright. - Local mail
- A cPanel host that thinks it runs mail for your domain keeps the message in a mailbox on the web server.
-
04
The receiver
Gmail, Outlook, your own mail host
- Trust
- It checks SPF, DKIM and DMARC against the From domain. Gmail requires every sender to pass SPF or DKIM.
- Policy
- If From is
jane@yahoo.com, Yahoo’s own DMARC policy decides, and it says reject.
-
05
The inbox
Or the spam folder
- Spam
- Accepted isn’t delivered to the inbox. Weak authentication and a From that doesn’t match its sender send form mail to spam.
- Silence
- Bounces go to the server’s envelope address, not to you, so nobody hears about a failure.
Why the visitor’s address can’t go in From
It feels natural: the message is from Jane, so From says Jane. But your server is sending it, not Yahoo’s, and DMARC lets each domain tell the world what to do with mail that claims to be from it and isn’t. Yahoo and AOL say reject. Your form’s message is exactly that mail.
The fix costs nothing. Send from an address on your own domain, and put the visitor in Reply-To: pressing Reply still writes to Jane. Contact Form 7’s default mail already does this, with Reply-To: [your-email] under Additional headers, and flags a From outside your domain with “Sender email address does not belong to the site domain.” WPForms warns that a From Email that doesn’t match your domain “can cause your notification emails to be blocked or marked as spam.”
| From address at | DMARC policy | Your server sends it |
|---|---|---|
| yahoo.com | p=reject | Receivers that follow DMARC refuse it. |
| aol.com | p=reject | Refused, the same as Yahoo. |
| icloud.com | p=quarantine | Filed as spam. |
| gmail.com | p=none; sp=quarantine | Up to the receiver, and Google asks senders not to do it. |
| outlook.com | p=none; sp=quarantine | Up to the receiver, and it still fails DMARC. |
| yourdomain.com | Yours | Passes, once SPF or DKIM is set up for it. |
Policies read from each domain’s _dmarc TXT record on 15 October 2026. Gmail’s sender guidelines add, in as many words: “Don’t impersonate Gmail From: headers.”
Why didn’t my form email arrive?
Answer ten questions.
Pick what’s true for your site; the causes re-rank as you go, each with the exact fix. If any copy of the message arrived anywhere, paste its headers too: the diagnoser reads SPF, DKIM, DMARC and the sending server from them. It all runs in your browser; nothing is sent anywhere.
Use a copy that reached any mailbox, a spam folder or a test address. Read only in this page.
The From address isn’t yours to send from
5 possible causes, ranked
-
01
The From address isn’t yours to send from
Most likely- The From line carries the visitor’s address, so the receiving server checks their domain’s DMARC policy against your server, and it fails. yahoo.com and aol.com publish p=reject; icloud.com p=quarantine.
Fix- 1Contact › Contact Forms › your form › Mail tab › From: an address on your own domain, such as [_site_title] <forms@yourdomain.com>.
- 2Additional headers: Reply-To: [your-name] <[your-email]>, so pressing Reply still writes to the visitor.
- 3Save. The warning “Sender email address does not belong to the site domain” should be gone.
-
02
PHP mail() on your server isn’t delivering
Likely- No SMTP plugin, so WordPress hands every message to PHP’s mail() function on your web server.
Fix- 1Install one SMTP plugin. WP Mail SMTP, FluentSMTP and Post SMTP are all free on WordPress.org.
- 2Connect it to a transactional email provider over its API, or SMTP on port 587 (2525 on WP Engine), and verify your domain with that provider.
- 3Set the plugin’s From address to one on your domain, and force it on every message.
- 4Send a test from the plugin (in WP Mail SMTP: Tools › Email Test), then submit the form.
-
03
It’s arriving, in spam
Worth checking- You haven’t looked in spam yet. It’s the quickest thing to rule out.
Fix- 1Mark the message “Not spam” and add the From address to your contacts, so the next ones land.
- 2Then fix why it was filed there: a From address on your own domain, with SPF, DKIM and DMARC published for it.
- 3Use a different address in From and To. WPForms advises against sending from and to the same one.
-
04
Your domain doesn’t vouch for the mail
Worth checking- You don’t know whether SPF and DKIM are set up. They decide whether mail from your domain is trusted, so check.
-
05
Nothing is saved, so failures are silent
Worth checking- Contact Form 7 doesn’t store submitted messages on its own, so unless you added Flamingo, a failed email is a lost message.
+− How the diagnoser decides
Each answer adds weight to the causes it points at: a visitor’s address in From weighs most, then spam actually found, a form error or a second mail plugin, then missing authentication, PHP mail() and the rest. Headers add evidence of their own: dmarc=fail, an SPF or DKIM result other than pass, authentication that passed for a domain other than your From, and the X-PHP-Originating-Script header PHP adds to mail sent through mail() when the host switches it on.
It reads the first Authentication-Results header, which is the one the receiving mailbox wrote, or Gmail’s Show original summary. The weights are rules of thumb for where to look first, not a verdict; the fixes in section 03 are worth doing whatever it says.
How to fix a WordPress contact form
that isn’t sending email.
In this order, because each step either finds the message or rules out a whole station. The first three take five minutes and change nothing on your site.
-
01
Find the message first
Before fixing anything, look for what was sent. Contact Form 7 doesn’t store submissions; its makers’ Flamingo plugin does. WPForms Lite doesn’t save entries to your database either; its Lite Connect backup keeps them on WPForms’ servers until you upgrade. On WordPress.com, the Form block keeps every response under Jetpack › Forms. Check the spam folder of the address you expect it at, too.
-
02
Check where it’s going
Contact Form 7: Contact › Contact Forms › your form › Mail, the To field. WPForms: form builder › Settings › Notifications, Send To Email Address. Both default to the WordPress admin email from Settings › General; make sure it’s an address someone reads.
-
03
Send a test that isn’t the form
Ask for a password reset for your own user, or send a test from an SMTP plugin (WP Mail SMTP: Tools › Email Test). If that arrives and the form doesn’t, the server can send and the form’s settings are the problem. If neither arrives, the server is.
-
04
Put your domain in From, the visitor in Reply-To
The single change that fixes most forms. In Contact Form 7, the Mail tab should read like this:
To: you@yourdomain.com From: [_site_title] <forms@yourdomain.com> Additional headers: Reply-To: [your-name] <[your-email]>WPForms: Notifications › From Email set to an address on your domain, and Reply-To set to the form’s Email field with the smart-tag button. An SMTP plugin’s own From setting (WP Mail SMTP calls it Force From Email) can override the form’s, so keep the two the same.
-
05
Publish SPF, DKIM and DMARC
So receivers can check that mail from your domain really is from you. One SPF record listing your host or email provider, the DKIM key your provider gives you, and a DMARC record at
_dmarcstarting atp=none. The SPF, DKIM and DMARC setup guide builds the records for you. -
06
Send through SMTP or an email API
Replace PHP mail() with a provider that signs your mail with your domain’s DKIM key. An SMTP plugin does it for every email WordPress sends, password resets and order emails included. Plugins and free tiers below.
-
07
Keep a copy and a log
So the next failure costs you an investigation, not a customer. Flamingo or your form’s entries keep the message; an email log keeps what WordPress tried to send and the error it got. FluentSMTP logs in its free version; WP Mail SMTP’s log is in Pro; WP Mail Logging (300,000+ installs) does nothing else.
-
08
Test again, properly
Submit the form to a personal Gmail address, open the message, choose Show original and look for PASS on SPF, DKIM and DMARC, or paste the headers into the diagnoser above. A score from a service such as mail-tester.com, which gives you an address to send to, checks the same things and the content.
Do you need an SMTP plugin
for WordPress email?
For mail that has to arrive, yes. An SMTP plugin swaps PHP’s mail() for a real email provider, which signs every message with your domain’s DKIM key and sends from servers with a reputation to keep. WP Mail SMTP’s own page puts it simply: WordPress relies on PHP mail() by default.
The plugin alone isn’t the fix. Installed with no mailer chosen, WP Mail SMTP still uses PHP mail(), and says so: its Default (none) mailer “won’t improve email deliverability.” Connect a provider, verify your domain with it, then test.
| Plugin | Active installs | Email log | Good for |
|---|---|---|---|
| WP Mail SMTP | 4+ million | Pro only | A setup wizard and built-in mailers for Mailgun, Postmark, Resend, SMTP2GO, Amazon SES, Gmail, Outlook and more. |
| FluentSMTP | 700,000+ | Free | Free email logs with full headers and the server’s reply, plus a fallback connection. |
| Post SMTP | 300,000+ | Free | Logs, failure alerts and a backup connection. |
| WP Mail Logging | 300,000+ | That’s all it does | Seeing what WordPress tried to send, and the error, before you change anything. |
Free tiers from transactional providers
One custom sending domain, one-day log retention.
Limited to 100 a day; three custom domains.
Free for as long as you like, by its own pricing page.
No overages on the free plan, and it doesn’t expire.
From each provider’s pricing page on 15 October 2026. A contact form rarely sends more than a few a day, so any of these covers it; all four have a built-in mailer in WP Mail SMTP. Your own Google Workspace or Microsoft 365 mailbox works too, through the plugin’s Gmail or Outlook mailer.
Hosts that limit WordPress email,
in their own words.
Managed WordPress hosts sell hosting, not email, and most say so. They send password resets well enough, then cap volume, change the sender, or close the port, and every one of them points you to a third-party provider.
WP Engine
Default WordPress mail goes through a third-party SMTP provider WP Engine manages, under a hard hourly limit it doesn’t publish. Port 25 isn’t allowed; it recommends a provider such as Mailgun, Gmail or Brevo, on port 2525 (587 and 465 also work).
Their docs →Kinsta
Transactional mail goes through MailChannels, capped per plan and shared across its sites. Kinsta says the service doesn’t currently support DMARC alignment, and to use a third-party SMTP service if you need it.
Their docs →WordPress.com
The Form block stores every response under Jetpack › Forms, so the message survives a lost email. Form and SMTP plugins need a paid plan, and its pricing page says every paid plan allows them.
Their docs →Cloud servers
Google Cloud blocks outbound connections to port 25 outside your network and recommends a third-party provider or a relay on 465 or 587. A server you run yourself needs an SMTP plugin, or it isn’t sending.
Their docs →cPanel hosting
With Email Routing on Local Mail Exchanger, the server “will always accept mail for the domain” and keep it in a local mailbox. If your mailboxes are elsewhere, choose Remote Mail Exchanger under Email › Email Routing.
Their docs →Read on each host’s documentation on 15 October 2026. WP Engine adds that it doesn’t provide MX or DKIM records; those come from whoever hosts your email.
A contact form that doesn’t
depend on email to reach you.
Every fix above makes the email more likely to arrive. The other way is not to need it. Builderify’s Message Us block, in the floating website widget, writes each message straight into your Builderify Inbox: no wp_mail(), no SMTP, no spam filter in between.
| WordPress form | Message Us block | |
|---|---|---|
| How it reaches you | An email, through PHP mail() or SMTP, past the receiver’s spam filter | Saved as a message in the Inbox mailbox you choose, the moment it’s sent |
| If delivery fails | Lost, unless the plugin saves entries | There’s no delivery step to fail |
| Replying | From your mail app, via Reply-To | From the Inbox, over your verified sending domain, threaded with the message |
| The sender | An email in your mailbox | Also kept as a lead; add a lead list and they’re asked to confirm before joining it |
| Where it sits | Anywhere on the page | Inside the floating widget, not as a form in your page |
Know this first
Inbox mailboxes are created on the sending domain you connect under Connect › Domains, and the block can’t be switched on until you pick one. Messages from the widget land in it straight away; your MX record doesn’t have to point at Builderify for them.
Replies go out from your domain, so they unlock once its DNS records verify and a person has approved the sender, usually within one business day. The SPF, DKIM and DMARC guide covers the records.
Each message shows up in the Inbox and the activity feed (“Jane messaged you from your website”), and on Telegram if you connect it. There’s no email alert, which would put you back on the path this page is about.
Message Us is a block in the floating bubble, next to whatever else you put there, such as live chat. If you need a form inside the page itself, keep your WordPress form and fix its email with the steps above.
If your account runs out of credits, the widget pauses until you top up, and the Message Us block with it.
Paste the widget’s script tag into the site header with a code plugin such as WPCode or Code Snippets. Block themes have no header.php, and theme updates overwrite edits to one.
- No per-message charge: you pay for the pages the widget loads on
- Name, email and message; phone and subject are optional fields
- Every sender kept as a lead of the block, or added to a list you pick
- No subscription; packs are one-time and never expire
The free credits are shared with every module you use. Full rate card on the pricing page; how leads and lists work.
Your WordPress form, an SMTP plugin, a log plugin and a lead-capture popup are four plugins doing one job between them. How many WordPress plugins is too many looks at which of yours one script can replace, and the OptinMonster alternative guide covers capturing leads without another account. When the email you send yourself bounces, the bounce code decoder says why.
Contact form email, before you ask.
Usually because WordPress hands the message to your web server's PHP mail() function, often with a From address that isn't on your domain, so the receiving server can't verify it and rejects it or files it as spam. Check the To address and the spam folder first, then put an address on your own domain in From, publish SPF, DKIM and DMARC, and send through an SMTP plugin connected to an email provider.
Because the From field holds an address on another domain, often the visitor's own email. Mail sent from your server with someone else's domain in From fails that domain's DMARC check; yahoo.com and aol.com tell receivers to reject it. Set From to an address on your site's domain and put Reply-To: [your-email] under Additional headers, so replies still go to the visitor.
Because the receiving server can't confirm your domain sent them. Most often the From address isn't on your domain, or the domain has no SPF and DKIM for the server that sends the mail. Use an address on your own domain in From, publish SPF, DKIM and a DMARC record, send through an SMTP provider, and check Gmail's Show original for PASS on all three.
For mail that has to arrive, yes. By default WordPress sends through PHP's mail() function, which many hosts limit or block. An SMTP plugin such as WP Mail SMTP, FluentSMTP or Post SMTP sends through an email provider instead, but only once you connect one: WP Mail SMTP's Default (none) mailer still uses PHP mail().
No. Contact Form 7 doesn't store submitted messages, so if the email fails, the message is gone. Its makers' free Flamingo plugin saves every submission in your WordPress dashboard. WPForms Lite doesn't save entries to your database either; its Lite Connect option backs them up to WPForms' servers until you upgrade.
Sources
- WordPress wp_mail() reference
- WordPress wp_mail() source, pluggable.php
- Contact Form 7 Default mail settings (source)
- Contact Form 7 Mail configuration validator (source)
- Contact Form 7 Flamingo plugin
- WPForms Troubleshooting email notifications
- WPForms Lite Connect entry backups
- WP Mail SMTP Plugin page
- FluentSMTP Plugin page
- WP Mail Logging Plugin page
- Google Email sender guidelines
- WP Engine Sending email on WP Engine
- Kinsta Transactional email
- WordPress.com Pricing and plugins
- WordPress.com Form block
- Google Cloud Sending email from an instance
- cPanel Email Routing
- PHP mail.add_x_header
- Mailgun Pricing
- SMTP2GO Pricing
- Postmark Pricing
- Resend Pricing
Read on 15 October 2026. Plugin defaults and messages are from Contact Form 7 6.2.2, WPForms Lite 2.0.2.2 and WP Mail SMTP 4.10.2; install counts from WordPress.org; DMARC policies measured in DNS the same day. ← All guides
Stop losing the visitors
you already paid for.
More leads from the traffic you already have, and follow-up that sends itself. Free to start. No card, no monthly fee.