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.

yahoo.com · aol.com DMARC p=reject Measured 15 Oct 2026

By the Builderify team

Illustration. The thank-you message only means WordPress handed the email on; WordPress’s own documentation says a true return value doesn’t mean the recipient got it.
01 / Why it fails

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.

  1. 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.
  2. 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.
  3. 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.
  4. 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.
  5. 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.”

DMARC policies of common mailbox domains, and what happens to form mail sent with them in From
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.”

02 / Diagnoser

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.

Your setup
Which form plugin?
Where is the site hosted?
What’s in the form’s From field?
Where should it arrive?
Does your domain have SPF and DKIM?
Do you use an SMTP plugin?
Is it in the spam folder?
Do password-reset emails arrive?
Are submissions saved in WordPress?
What does the form show after Send?

Use a copy that reached any mailbox, a spam folder or a test address. Read only in this page.

Most likely cause

The From address isn’t yours to send from

5 possible causes, ranked

  1. 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
    1. 1Contact › Contact Forms › your form › Mail tab › From: an address on your own domain, such as [_site_title] <forms@yourdomain.com>.
    2. 2Additional headers: Reply-To: [your-name] <[your-email]>, so pressing Reply still writes to the visitor.
    3. 3Save. The warning “Sender email address does not belong to the site domain” should be gone.
  2. 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
    1. 1Install one SMTP plugin. WP Mail SMTP, FluentSMTP and Post SMTP are all free on WordPress.org.
    2. 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.
    3. 3Set the plugin’s From address to one on your domain, and force it on every message.
    4. 4Send a test from the plugin (in WP Mail SMTP: Tools › Email Test), then submit the form.
    Pick an SMTP plugin and provider →
  3. 03

    It’s arriving, in spam

    Worth checking
    • You haven’t looked in spam yet. It’s the quickest thing to rule out.
    Fix
    1. 1Mark the message “Not spam” and add the From address to your contacts, so the next ones land.
    2. 2Then fix why it was filed there: a From address on your own domain, with SPF, DKIM and DMARC published for it.
    3. 3Use a different address in From and To. WPForms advises against sending from and to the same one.
    SPF, DKIM and DMARC, step by step →
  4. 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.
  5. 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.
Read from your headers
+ 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.

03 / Fix in order

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.

  1. 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.

  2. 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.

  3. 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.

  4. 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.

  5. 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 _dmarc starting at p=none. The SPF, DKIM and DMARC setup guide builds the records for you.

  6. 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.

  7. 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.

  8. 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.

04 / SMTP

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.

Free WordPress SMTP and email log plugins compared
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

Mailgun 100 a day

One custom sending domain, one-day log retention.

Resend 3,000 a month

Limited to 100 a day; three custom domains.

SMTP2GO 1,000 a month

Free for as long as you like, by its own pricing page.

Postmark 100 a month

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.

05 / Your host

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.

Hard hourly limit

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 →
150 to 3,000 a day

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 →
Responses saved

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 →
Port 25 closed

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 →
Local mail

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.

06 / Skip the 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.

A WordPress contact form compared with Builderify's Message Us block
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

It needs a mailbox on your domain

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 need a verified, reviewed domain

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.

You’re told in the app, not by email

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.

It lives in the widget

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.

It stops when your credits do

If your account runs out of credits, the widget pauses until you top up, and the Message Us block with it.

Installing it on WordPress

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.

Message Us on BuilderifyCredits
A message received0
1,000 widget page loads10
Free every month250
Page loads that covers25,000
Starter pack, $9100,000 loads
  • 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
Start free

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.

Questions

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.

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.