Blog
WordPress Contact Form Not Sending Email? How to Fix It (and Stop Losing Leads)
If your WordPress form says “thank you” but nothing shows up in your inbox, you’re losing leads without knowing it. Here’s why it happens, how I test it in two minutes, and the fixes that actually last.
Caleb Dorris 27 October 2026, 4:27 PM Updated 30 October 2026 14 min

The short version
Your form can say “sent” and still lose the lead.
- Why it happens: by default WordPress hands mail to your web server’s PHP
mail()function. Gmail and Outlook trust that kind of unauthenticated mail less and less, so it lands in spam or vanishes. - The real fix: send through an authenticated mail service (SMTP or a mail API), use a From address on your own domain, put the visitor in Reply-To, and set up SPF, DKIM and DMARC.
- The safety net: save every submission in the database and log failures, so a mail problem never means a lost customer.
Here’s a message every web developer has gotten some version of: “I think my website form is broken. A customer told me they filled it out last week and never heard back.”
That’s the worst way to find out. Nothing looks wrong. The form still shows a nice green “Thank you, we’ll be in touch.” WordPress doesn’t warn you. The email just never got there, or it went to a spam folder nobody checks. Every one of those is someone who was ready to hire you and then called the next business on Google.
The good news is that this is one of the most fixable problems on a WordPress site. Below is how I diagnose it and what I set up so it doesn’t come back. This works whether you’re on Contact Form 7, WPForms, Elementor forms, Gravity Forms or something custom. You can do most of it yourself. If you’d rather not, I’ll tell you at the end how I can help.
Short on time? I fix this for small businesses. Get a free quote, or read on and do it yourself.
The 2-minute test: is it actually broken?
Before you change anything, find out what’s really happening. You need two inboxes: the one the form sends to (usually your business address), and a personal Gmail or Outlook address you control.
- Submit your own form with your personal email in the email field and a message like “Test 1, 9:42 AM.”
- Check the business inbox, including spam/junk, for the next five minutes or so.
- Temporarily change the form’s recipient to your personal Gmail and submit again (“Test 2”). Then check that inbox and its spam folder too.
- If one arrived, open it and look at the full headers. In Gmail that’s the three-dot menu, then “Show original.” Near the top you’ll see SPF, DKIM and DMARC each marked PASS, FAIL or missing.
Now you know which of three situations you’re in:
- Nothing arrives anywhere. The server isn’t sending at all. That’s usually a host that blocks or limits PHP mail, or a broken configuration. Start with Fix 1.
- It arrives, but in spam. The mail is going out but it isn’t trusted. That’s an authentication and From-address problem: Fixes 1 to 3.
- It arrives in Gmail but not in your business inbox. Your own mail server or its filters are rejecting it. This is common when the website and the email are hosted in different places. Fix 3, and check your email provider’s quarantine.
Put your recipient back the way it was when you’re done.
Why WordPress email fails in the first place
WordPress sends all of its email (contact forms, password resets, new-order notices) through one function, wp_mail(). Under the hood, WordPress’s own source code sets PHPMailer to use PHP’s built-in mail() unless a plugin changes it. In plain English: by default your web server tries to send the email itself, with no login to any real mail service (WordPress developer reference: wp_mail()).
That made sense in 2005. Today it causes three problems:
- Your web server isn’t a trusted mail server. It’s often a shared IP address that other sites also send from. Gmail and Outlook have no reason to believe it’s allowed to send for your domain.
- The big inbox providers now require authentication. Since February 1, 2024, Google has required everyone who sends to Gmail accounts to set up SPF or DKIM for their sending domain. Bulk senders (more than 5,000 messages a day to Gmail) need SPF, DKIM and DMARC (Google, Email sender guidelines). A contact form isn’t a bulk sender, but the baseline still applies.
- “Sent” doesn’t mean “delivered.” WordPress’s own docs say it plainly: a true return value from
wp_mail()“does not automatically mean that the user received the email successfully.” It only means the server accepted the request (wp_mail() reference). That’s why your form shows a success message even when the email went nowhere.
There’s one more classic trap. If nothing else sets a From address, WordPress defaults to wordpress@yourdomain.com, and a comment in WordPress’s own source warns that some hosts will block outgoing mail from that address if the mailbox doesn’t exist.
Fix 1: Send through a real mail service (SMTP or a mail API)
This is the fix that matters most. Instead of letting the web server send mail on its own, you have WordPress log in to a real mail service and send through it. Options, roughly in the order I’d look at them:
- Your existing business email provider. If you’re on Google Workspace or Microsoft 365, they offer ways to send from applications. Setup depends on your plan and your provider’s current security settings, so follow their current docs. Some of these setups change over time as providers retire older login methods.
- A transactional email service. Services like Amazon SES, Postmark, Mailgun, SendGrid or Brevo are built for exactly this: apps sending one-off messages. You verify your domain with them, they give you DNS records to add, and you get delivery logs. Most have a free or low-cost tier; check their current pricing pages, because those change.
- Your host’s SMTP server. This is fine if your host provides authenticated SMTP and your domain’s DNS is set up for it, but it’s usually the weakest of the three.
To connect WordPress, you can use an SMTP plugin (WP Mail SMTP, FluentSMTP and Post SMTP are common), or, on sites I build, a few lines in a small plugin that hooks phpmailer_init, which WordPress fires right before it sends. Either way, keep the SMTP password or API key out of the database if you can: put it in wp-config.php or an environment variable, not in a settings screen any admin user can read.
Then send a test. Most SMTP plugins have a “send test email” button that shows the actual error if something’s wrong, which is much more useful than a form that just says “thank you.”
Fix 2: Use your own domain in From, and put the visitor in Reply-To
This is the form-settings mistake I’d check first: the form is set so the email comes From the visitor’s address. Jane fills out the form, and the notification claims to be from jane@gmail.com, even though your web server sent it.
To Gmail, that looks exactly like spoofing, because it is. Your server isn’t allowed to send as gmail.com. The Contact Form 7 author makes the same point in the plugin’s docs: in the From field, “use an email address that belongs to the same domain as the site” (Contact Form 7, Best practice to set up mail).
The right setup:
- From: something on your domain, like
website@yourbusiness.comorforms@yourbusiness.com. Make it a real mailbox or alias. - Reply-To: the visitor’s email from the form. When you hit Reply, it goes to them, which is what you wanted all along.
- To: the person who actually answers leads. If that’s more than one person, consider a shared inbox or alias instead of a long CC list.
Every major form plugin has these fields. In Contact Form 7, Reply-To goes in the “Additional headers” box of the Mail tab. In WPForms and Elementor, look for “From Email” and “Reply-To” in the form’s notification settings.
Also check the boring stuff: make sure the recipient address doesn’t have a typo and still exists. And if the form uses optional fields in headers or the subject, make sure the email still makes sense when someone leaves those fields blank. The CF7 docs warn that an empty or very short message body can look like spam, and on some hosts it can make sending fail.
Fix 3: SPF, DKIM and DMARC (and the one-SPF-record trap)
These are three DNS records that tell the world who is allowed to send email for your domain. Your mail service (from Fix 1) will tell you exactly what to add; here’s what each one does so the instructions make sense:
- SPF is a list of servers allowed to send for your domain. It’s a TXT record that starts with
v=spf1. - DKIM is a digital signature on each message, checked against a public key you publish in DNS.
- DMARC ties them together. It checks that the domain in the From line lines up with the domain that passed SPF or DKIM (the spec calls this “identifier alignment”), and tells receivers what to do when it doesn’t (RFC 7489, DMARC).
Two SPF mistakes are easy to make, and both come straight from the SPF standard:
- Two SPF records. If your domain publishes more than one
v=spf1record, the check returns a “permerror” instead of a pass (RFC 7208, SPF). This tends to happen when someone adds a new service by creating a second record instead of adding aninclude:to the existing one. Merge them into one record. - Too many lookups. SPF checkers must stop after 10 DNS-querying terms (
include,a,mx,ptr,exists,redirect) and return “permerror” if there are more (RFC 7208, section 4.6.4). A business that has added email, a CRM, an invoicing tool and a newsletter service over the years can hit this without noticing.
For DMARC, I start new setups with a monitoring-only policy (p=none) and a reporting address, watch the reports for a couple of weeks to make sure every legitimate sender passes, then tighten it. Going straight to a strict policy is how people accidentally block their own invoices.
Then repeat the 2-minute test and open “Show original” again. You want SPF, DKIM and DMARC all to say PASS.
Fix 4: Stop trusting email alone
Even with perfect setup, email is the wrong place to keep the only copy of a lead. Mailboxes fill up, filters change, passwords expire, people leave. So I always add a safety net:
- Save every submission to the database. Contact Form 7’s own docs say it “doesn’t store submitted messages anywhere” and recommend Flamingo, a free plugin from the same author, so you don’t “lose important messages forever” (Contact Form 7, Save submitted messages with Flamingo). Other form plugins have entry storage built in or on a paid tier, so check yours.
- Log failures. WordPress fires a
wp_mail_failedaction whenever PHPMailer throws an error (WordPress developer reference: wp_mail_failed). Most SMTP plugins also keep an email log. On sites I build, I like to wire a failed send to an alert, so someone hears about it before the customer does. - Send the lead somewhere besides email. A text message, a Slack or Teams message, a row in a Google Sheet, or straight into your CRM. Then a mail problem slows you down instead of costing you the job.
- Send the visitor a confirmation. A short auto-reply (“Got it, we’ll call you today”) reassures them, and if they don’t get it, they’re more likely to call you instead of silently moving on.
Plugin-specific gotchas I see a lot
- Contact Form 7: the default template’s From line uses
wordpress@yourdomain. The CF7 author recommends creating that mailbox for real or changing the From to an address you own. Also check the “Mail (2)” auto-reply. If it’s on and sending From the visitor’s address, fix it the same way. - WPForms, Elementor, Gravity Forms and others: they all hand mail to WordPress’s
wp_mail()in the end, so the SMTP and DNS fixes above apply to all of them. Their own notification screens are where the From and Reply-To mistakes live. - Two SMTP plugins at once: two mail plugins can end up fighting over the same hook. Pick one and remove the other.
- After a migration or host change: mail breaks a lot right after a move, because the new server has a different IP, your SPF record still points at the old host, or the new host blocks PHP mail. If it broke the same week you moved, start there.
- It suddenly changed and you didn’t touch anything: if your site also started sending email you didn’t write, or new admin users appeared, treat it as a possible compromise. Here’s how I audit a WordPress site after a plugin compromise.
My contact form delivery checklist
This is the list I’d run on any site. Copy it and check yours.
- A test submission arrives in the business inbox (not spam) within a few minutes.
- WordPress sends through an authenticated SMTP server or mail API, not PHP
mail(). - The SMTP password or API key lives in
wp-config.phpor the environment, not an admin settings page. - The From address is on your own domain; the visitor’s email is in Reply-To.
- Your domain has exactly one SPF record, and it includes your mail service.
- DKIM is set up for your mail service, and DMARC is published (start with
p=noneand reports). - Every submission is also saved somewhere other than email (database entries, CRM, sheet).
- Failed sends are logged, and someone gets alerted.
Re-run number 1 after any plugin update, host move, DNS change or email provider change. It takes two minutes and it’s the cheapest insurance you’ll ever buy for your leads.
What I set up for clients (and how I can help)
When a small business brings me this problem, the fix usually isn’t a rebuild: connect a proper mail service, clean up the DNS records, correct the form’s From and Reply-To, add entry storage and failure alerts, and test from a few different inboxes. If the site is older, I’ll also check the PHP version and plugins while I’m in there, because mail problems and outdated PHP often show up together.
Sometimes the form is the wrong tool altogether. If leads should go straight into your CRM or calendar, get a text alert, or kick off a quote, I build that too: custom WordPress plugins, small Next.js apps and integrations with the tools you already use.
Need a hand?
Form still not delivering? I’ll track it down.
Honestly, it’s rarely one big thing. It’s usually two or three small ones stacked up: a server sending mail nobody authenticated, a From address that isn’t yours, a DNS record that’s missing or doubled up, and no backup copy of the lead. That’s why I test from a few inboxes instead of guessing.
How I handle it:
- Find where the mail actually goes. Test submissions to a few inboxes, a look at the headers, and a check of what the form, the server and your DNS are doing.
- Fix the sending, not just the symptom. An authenticated mail service, your own domain in From and the visitor in Reply-To, and SPF, DKIM and DMARC cleaned up.
- Add a safety net, then test again. Every submission saved, failed sends logged with an alert, and the test re-run from several inboxes.
The aim is that every lead lands somewhere you’ll see it. I can’t control Gmail’s spam filter, but I can set your mail up the way the big inbox providers ask for, so a lead never lives only in an email. If this sounds like your site, get a free quote, or email me at caleb@calebdorris.com with your site’s URL and the page your form is on. I usually reply within a couple of hours.
Caleb Dorris, senior software developer in Nashville
FAQ
Why is my WordPress contact form not sending emails?
Usually because WordPress is using your web server’s PHP mail() function, which many hosts limit and which Gmail and Outlook don’t trust. Send through an authenticated SMTP server or mail API, and set up SPF, DKIM and DMARC for your domain.
Why do my contact form emails go to spam?
The most common causes are a From address that isn’t on your domain (often the visitor’s own email), missing or broken SPF/DKIM/DMARC records, and sending from a shared web server. Use your own domain in From, put the visitor in Reply-To, and authenticate your domain.
Do I need an SMTP plugin for WordPress?
You need WordPress to send through a real, authenticated mail service. An SMTP plugin is the easiest way to do that. A developer can also do it with a few lines of code on the phpmailer_init hook. Either is fine; what matters is not relying on PHP mail().
Should the From address be the visitor’s email?
No. Use an address on your own domain as From, and put the visitor’s email in Reply-To. Sending From the visitor’s address looks like spoofing and is a common reason form emails get filtered.
How do I know if I’ve been missing leads?
Submit your own form and check the inbox and spam. Then check whether your form plugin stores entries in the database. If it does, compare those entries against the emails you actually received. If it doesn’t, turn on entry storage now so you can tell from here on.
Sources
Need a web developer in Nashville?
PHP, WordPress and Next.js. Free quote, and I usually reply within a couple of hours.
caleb@calebdorris.com and call or text (615) 914-1073