Contact form submissions never arrive. Password reset links never reach users. WooCommerce order confirmations vanish, and customers email asking whether their purchase went through.
WordPress reports no error. The form shows a success message. Nothing in the dashboard suggests a problem. This is one of the most common failures on self-hosted WordPress sites, and it is almost never caused by the plugin you are blaming.
The cause is how WordPress sends mail by default. This guide explains what actually happens when wp_mail() runs, why hosting providers block it, and how to configure authenticated SMTP so email delivery stops being something you have to keep fixing.
Quick Answer: Why Is WordPress Not Sending Email?
WordPress uses the PHP mail() function by default. That function sends mail directly from your web server with no authentication, which most hosting providers block and most mailbox providers reject or filter as spam.
The fix is to route WordPress mail through an authenticated SMTP service instead:
// wp-config.php
define( 'SMTP_HOST', 'smtp.photonrelay.com' );
define( 'SMTP_PORT', 587 );
define( 'SMTP_USER', 'your_project_api_user' );
define( 'SMTP_PASS', 'your_secret_api_key' );
define( 'SMTP_FROM', 'noreply@yourdomain.com' );
define( 'SMTP_NAME', 'Your Site Name' );
You can apply this with a plugin or with a small amount of code, both covered below. Either way, the change that matters is the same: WordPress stops sending mail itself and starts handing it to a service that is authorised to send on your domain’s behalf. An authenticated relay such as PhotonConsole handles that authorisation.
What wp_mail() Actually Does

Every email WordPress sends — registration notices, password resets, comment notifications, plugin alerts, WooCommerce receipts — passes through a single function called wp_mail().
Internally, wp_mail() uses PHPMailer. By default PHPMailer is configured to use PHP’s built-in mail() function, which hands the message to whatever mail transfer agent exists on the web server. On most shared hosting and cloud servers there either is no properly configured agent, or the one that exists sends from an IP address with no sending reputation.
The message leaves. It just never arrives. If you want the underlying protocol explained first, see our guide to what SMTP is.
Why WordPress Email Fails
Most email delivery failures on WordPress come down to authentication and server configuration rather than faults in WordPress itself. These are the causes worth checking, in order.
1. No Authentication on the Sending Domain
Without SPF and DKIM records, receiving mail servers cannot verify that your web server is allowed to send as your domain. Gmail, Outlook and Yahoo respond by filtering the message into spam or rejecting it outright, in line with Google’s sender guidelines. This is the single most common cause. Our guide to SPF, DKIM and DMARC covers the records in detail, and you can check what your domain currently publishes with the free email deliverability checker.
2. The Default From Address Does Not Exist
WordPress sends from wordpress@yourdomain.com unless a filter tells it otherwise. That mailbox usually does not exist, which means bounces go nowhere and DMARC alignment fails. Mailbox providers treat mail from a non-existent sender with suspicion.
3. Your Host Has Disabled the mail() Function
Many hosts disable PHP mail() entirely to prevent spam originating from compromised sites. When this happens wp_mail() returns false, but most plugins do not surface that failure to the user.
4. Hourly Sending Limits on Shared Hosting
Shared hosting plans commonly cap outbound mail per hour. A store processing orders, or a site with an active membership area, hits that ceiling and the remaining mail is silently discarded for the rest of the hour.
5. Outbound SMTP Ports Are Blocked
Cloud providers including AWS, Google Cloud and DigitalOcean block outbound port 25 by default, and some block 587 as well. AWS documents its port 25 throttle removal process, though removal does not solve the reputation problem underneath.
Quick Fix
WordPress Sends No Email At All
- Install an SMTP plugin and send its built-in test email to see the real error
- Confirm your host has not disabled the PHP
mail()function - Set a from address that exists on your domain, not
wordpress@ - Check your domain publishes SPF and DKIM records
- Try port 2525 if your host blocks 587 and 465
Two Ways to Configure SMTP in WordPress
Both approaches do the same thing. Choose based on who maintains the site.
| Method | Best for | Trade-off |
|---|---|---|
| SMTP plugin | Most sites, non-developers, client handovers | Another plugin to keep updated; credentials stored in the database |
| Code in an mu-plugin | Developer-managed sites, version-controlled deployments | No interface for the site owner; requires file access to change |
Method 1: Using an SMTP Plugin
Install a mail SMTP plugin, open its settings, and enter the connection details:
- Mailer: Other SMTP
- SMTP Host: smtp.photonrelay.com
- Encryption: TLS
- SMTP Port: 587
- Authentication: On
- Username and Password: your relay credentials
- From Email: an address on your own domain
- From Name: your site name
Then send the plugin’s test email before assuming it works. Most SMTP plugins display the raw server response, which tells you immediately whether the failure is authentication, connection or delivery.
Method 2: Using Code
Add the credentials to wp-config.php so they sit outside the database:
// wp-config.php — add above the "That's all, stop editing" line
define( 'SMTP_HOST', 'smtp.photonrelay.com' );
define( 'SMTP_PORT', 587 );
define( 'SMTP_USER', 'your_project_api_user' );
define( 'SMTP_PASS', 'your_secret_api_key' );
define( 'SMTP_FROM', 'noreply@yourdomain.com' );
define( 'SMTP_NAME', 'Your Site Name' );
Then create wp-content/mu-plugins/smtp-config.php:
<?php
/**
* Route wp_mail() through an authenticated SMTP relay.
*/
add_action( 'phpmailer_init', function ( $phpmailer ) {
$phpmailer->isSMTP();
$phpmailer->Host = SMTP_HOST;
$phpmailer->Port = SMTP_PORT;
$phpmailer->SMTPAuth = true;
$phpmailer->Username = SMTP_USER;
$phpmailer->Password = SMTP_PASS;
$phpmailer->SMTPSecure = 'tls'; // 'ssl' if using port 465
$phpmailer->From = SMTP_FROM;
$phpmailer->FromName = SMTP_NAME;
} );
// Make sure WordPress itself stops using wordpress@yourdomain.com
add_filter( 'wp_mail_from', function () {
return SMTP_FROM;
} );
add_filter( 'wp_mail_from_name', function () {
return SMTP_NAME;
} );
Common Mistake
Putting this code in your theme’s functions.php. It will be wiped the next time the theme updates, and it stops working entirely if anyone switches themes. Email then breaks weeks later with no obvious cause. Use an mu-plugins file instead — it loads automatically, cannot be deactivated by accident, and survives theme changes.
Step 3: Add Your DNS Records
SMTP credentials alone are not enough. Your domain also has to state that the relay is allowed to send on its behalf.
TXT @ v=spf1 include:relay.photonconsole.com ~all
CNAME photon._domainkey dkim.photonconsole.com
Note
DNS changes are not instant. SPF and DKIM records can take from a few minutes to 24-48 hours to propagate depending on your registrar and TTL settings. Confirm propagation with a lookup tool before assuming a record is wrong. Also check you do not already have a second SPF record — publishing two separate records starting with v=spf1 breaks authentication completely.
Step 4: Send a Real Test
Use your SMTP plugin’s test function, or trigger a genuine password reset. Then confirm the message passed authentication rather than simply arriving. Tools such as Mail Tester score a real send and show SPF and DKIM results, and MXToolbox confirms your DNS records resolve as intended.
Fixing WooCommerce Order Emails

WooCommerce sends order confirmations, processing notices and shipping updates through wp_mail(), so everything above applies. There are a few additional causes specific to stores.
- Emails disabled in settings. Check WooCommerce, then Settings, then Emails, and confirm each notification is enabled with a valid recipient.
- Order status never changes. Customer emails fire on status transitions. If an order sits at pending payment, no confirmation is triggered because the transition never happened.
- WP-Cron not running. Some notifications are scheduled rather than immediate. On low-traffic sites WP-Cron may not fire, so scheduled mail never sends. Replacing WP-Cron with a real server cron job resolves this.
- Volume against hourly caps. A store sending order, invoice and shipping mail for every purchase reaches shared hosting limits quickly.
For stores sending at volume, our ecommerce email infrastructure page covers the requirements in more depth.
Quick Fix
WooCommerce Order Emails Not Arriving
- Confirm the specific email type is enabled under WooCommerce settings
- Place a test order and check the order status actually changes
- Check the customer email address on the order is correct and deliverable
- Replace WP-Cron with a server cron job for scheduled notifications
- Install a mail logging plugin so you can see whether WordPress attempted the send
Contact Form Delivery
Contact form plugins hand their mail to wp_mail() as well, so a configured SMTP connection fixes most form delivery problems too. Two settings still cause failures after SMTP is working.
The From field. Setting the form’s from address to the visitor’s own email address causes SPF and DMARC failures, because your server is not authorised to send as their domain. Send from your own address and put the visitor’s address in Reply-To instead.
Notification recipients on free mail providers. Sending notifications to a Gmail or Yahoo address from your own domain is more likely to be filtered than sending to an address on the same domain you send from.
Port Reference
| Port | Encryption | When to use |
|---|---|---|
| 587 | TLS | Recommended default for WordPress |
| 465 | SSL | When the provider requires implicit SSL |
| 2525 | TLS | When the host blocks 587 and 465 |
| 25 | None | Avoid — blocked by nearly all hosts |
Configuring WordPress With PhotonConsole
The settings below work with either the plugin method or the code method above.
SMTP Host: smtp.photonrelay.com
SMTP Port: 587 (465 for SSL, 2525 if 587 is blocked)
Encryption: TLS
Authentication: On
Username: your_project_api_user
Password: your_secret_api_key
From Address: noreply@yourdomain.com
From Name: Your Site Name
Port 2525 exists specifically for hosts that block the standard SMTP ports, which resolves the shared hosting and cloud provider problems described earlier. Every PhotonConsole account includes 5,000 free emails per month, which is enough for most WordPress sites to run indefinitely without paying anything, and enough for a store to validate the full setup before committing. Details are on the PhotonRelay page, and pricing has no monthly minimum.
If you are comparing options first, our analysis of free SMTP servers covers where each one stops being practical.
Host-Specific Notes
Shared Hosting and cPanel
Check your hourly mail limit in the hosting control panel before assuming a configuration fault. Sending through an external relay bypasses that cap entirely, because the mail no longer leaves through your host’s mail server.
Managed WordPress Hosting
Several managed hosts disable mail() by policy and expect you to connect an external SMTP service. Check the host’s documentation before spending time debugging — on these platforms SMTP is the intended configuration, not a workaround.
Local Development
Use a mail catcher such as Mailpit or MailHog rather than sending real messages from a local environment. Local machines have no sending reputation, and test emails to real addresses can create spam complaints against your domain.
Multisite
An mu-plugin applies across the whole network, so a single configuration file covers every site. Confirm each site’s from address uses a domain you have authenticated, particularly when sites use mapped domains.
Pro Tips
- Install a mail logging plugin. Without a log there is no way to tell whether WordPress attempted a send at all, which is the first thing you need to know.
- Use a subdomain for site mail. Sending from
mail.yourdomain.comkeeps your site’s sending reputation separate from your business email. - Store credentials in
wp-config.php, not the database. A plugin storing an SMTP password in the options table exposes it to any admin user and to database exports. - Test after every migration. Moving hosts changes the sending IP and often the available ports. Email is one of the first things to break and one of the last things anyone checks.
- Keep transactional and marketing mail separate. A newsletter plugin sending through the same connection as your order confirmations puts both at risk if complaint rates rise.
- Re-check DNS after registrar changes. Moving DNS providers frequently drops TXT records, and SPF disappears without anyone noticing until delivery drops.
Related Issues You May Hit Next
- SMTP authentication errors when credentials are rejected despite looking correct
- SMTP not working across the ten most common failure modes
- Emails landing in Gmail spam despite sending successfully
- Emails sent but not delivered when the server reports success
- SMTP connection timeouts when the connection hangs
Frequently Asked Questions
Do I need a plugin to fix WordPress email?
No. A plugin is the easiest route for most sites, but the same result can be achieved with a small mu-plugin and credentials in wp-config.php. The plugin is a convenience, not a requirement.
Why do my emails arrive in spam instead of the inbox?
Delivery and inbox placement are different things. A successful send only means the receiving server accepted the message. Missing SPF or DKIM records, or a from address that does not exist, are the usual reasons a delivered message still lands in spam.
Can I use Gmail to send WordPress email?
For a small personal site, yes. For anything transactional, no. Google enforces low daily sending caps, throttles automated traffic, and can lock the account, which takes your password reset emails down with it.
Why did email work before and suddenly stop?
The three usual causes are a host migration that changed the sending IP, a DNS change that dropped the SPF record, or a theme update that removed code from functions.php. Check what changed around the date delivery stopped.
Does WordPress email failure affect security?
Yes. If password reset emails do not arrive, locked-out administrators cannot regain access, and users cannot recover accounts. Email delivery is part of your site’s authentication path, not just a notification feature.
How many emails can WordPress send per hour?
WordPress itself sets no limit. The cap comes from your hosting provider, and on shared hosting it is often between 50 and 500 per hour. Sending through an external relay removes that restriction.
Should the from address match my domain?
Yes, and the mailbox should exist. A from address on a domain you have authenticated, with a real inbox behind it, passes authentication checks and gives bounces somewhere to go.
Conclusion
WordPress email problems feel unpredictable because the failure is silent. The form submits, the order completes, the reset is requested, and nothing surfaces to say the message never left. Once you know that wp_mail() defaults to an unauthenticated PHP function, the behaviour stops being mysterious.
The permanent fix has two halves, and both are needed. Route WordPress mail through an authenticated SMTP connection so the message is sent properly, and publish SPF and DKIM records so receiving servers trust it. Doing only the first still leaves mail in spam folders. Doing only the second changes nothing, because the mail is still coming from an unauthenticated server.
Once both are in place, WordPress email stops being a recurring problem. A dedicated transactional email solution handles the authentication, routing and sending reputation, and works with the plugin or the code method shown above. Developers working on other stacks may also want our guides to sending email in Node.js and sending email in Python.

