Most WordPress sites cannot send email reliably out of the box. The default configuration depends on PHP’s mail() function, which in turn depends on the server having a working mail transfer agent, and most modern hosting environments either lack one or actively block outbound mail. The result: password reset emails vanish, contact form submissions disappear, WooCommerce order confirmations never arrive, and the site administrator finds out only when a customer complains.
Fixing this requires understanding the delivery chain, then replacing the broken link. The chain runs: WordPress wp_mail() → PHP mail() → local MTA (sendmail/Postfix) → recipient’s MX server. On most hosts, the chain breaks at step two or three. The fix is to bypass the local MTA entirely by routing mail through an external email service via SMTP or API, using a mailer plugin to make the connection.
One scope note: this covers transactional email: the messages WordPress generates automatically (password resets, form notifications, order confirmations, admin alerts). Marketing email (newsletters, drip campaigns, broadcast sends) uses separate infrastructure (Mailchimp, ConvertKit, MailerLite, and similar) and is not covered here. The two systems are distinct; setting up transactional email does not give a site newsletter capability, and vice versa.
Why WordPress email breaks
WordPress sends all its email through a single PHP function: wp_mail(), defined in wp-includes/pluggable.php. Under the hood, wp_mail() uses the PHPMailer library (bundled with WordPress core since the early 2.x releases; upgraded to PHPMailer 6 in WordPress 5.5) to compose and dispatch messages. By default, PHPMailer calls PHP’s native mail() function, which hands the message to whatever mail transfer agent the server’s sendmail_path directive points to, typically sendmail or Postfix on Linux hosts.
This default path fails for three common reasons:
The host blocks outbound mail. Cloud infrastructure providers block SMTP ports by default on new instances to prevent abuse, but the specifics vary. DigitalOcean blocks ports 25, 465, and 587 on all Droplets (all three standard mail submission ports), leaving API-based sending through an external service as the only option. AWS EC2 restricts port 25 to private IP addresses by default (a request can be submitted to lift this), but allows 587 and 465. Google Cloud Compute and Azure VMs similarly block port 25 while leaving 587 and 465 open. A WordPress site on a fresh DigitalOcean Droplet cannot send mail over SMTP at all; on AWS, GCP, or Azure, it can send via ports 587 or 465 once an external service is configured.
The host provides no MTA. Many managed WordPress hosts and containerised environments ship without sendmail or Postfix installed. PHP’s mail() function returns false, WordPress logs nothing by default, and messages silently fail. The site appears to work (pages load, plugins activate), but email is dead.
The host’s MTA sends mail, but it lands in spam. Even hosts that do provide a working MTA typically send from a shared IP address with no SPF, DKIM, or DMARC records for the sending domain. Receiving servers (Gmail, Outlook, Yahoo) see an unauthenticated message from an IP shared by hundreds of unrelated sites, and route it accordingly: the spam folder, or the void.
The practical upshot: relying on the default WordPress email path is viable only on the small subset of hosting providers that explicitly provision and maintain outbound email for their customers. Kinsta is the best-known example, offering
transactional email as part of its hosting package via MailChannels with proper authentication. WordPress.com-hosted sites and Pressable (both Automattic properties) handle outbound email natively as well. These are exceptions. For the majority of hosts (shared, VPS, and managed alike), the fix is to route mail through an external service.
The fix: external service + mailer plugin
The solution has two parts:
- An external email service that accepts messages from the WordPress site and delivers them to recipients. These services maintain their own sending infrastructure with dedicated IP addresses, established sender reputation, and authentication already configured.
- A mailer plugin that connects WordPress to that service. The plugin hooks into
wp_mail(), replacing the default PHPMailer transport with either an SMTP connection or the service’s HTTP API.
Choosing an email service
For a site that just needs email to work, Brevo’s free tier is the lowest-friction starting point. It allows 300 emails per day, more than enough for most WordPress sites, requires no credit card, and connects through both SMTP and API. SMTP2GO provides 1,000 emails per month on its free plan with a clean dashboard and solid documentation. Mailgun offers 1,000 per month on its flex plan, though Mailgun’s pricing structure rewards careful reading beyond the first month.
For sites with higher volume or stricter deliverability requirements, nanoPost maintains a curated comparison of SMTP email services with per-provider details on pricing, free tiers, API support, and WordPress integration.
A WordPress site sending through any reputable external service will deliver more reliably than one sending through a shared host’s MTA.
Choosing a mailer plugin
The mailer plugin replaces the default wp_mail() transport: instead of handing messages to PHP’s mail() function, the plugin sends them over SMTP or via the service’s API endpoint.
WP Mail SMTP is the most widely installed and the easiest first choice for a site that wants setup done in under five minutes. FluentSMTP is the better pick for site operators uncomfortable with Awesome Motive’s upselling; the free version covers everything most sites need and the codebase is genuinely open source. Post SMTP stands out for its failure-alert notifications (including Slack and mobile push) and log management. All three connect to every major email service. nanoPost’s mailer plugin comparison covers the full field.
Once configured, the plugin’s effect is global: every call to wp_mail(), from WordPress core, from WooCommerce, from contact form plugins, from any plugin that uses the standard WordPress email function, routes through the external service automatically.
For those who prefer to skip the plugin entirely and configure the SMTP connection in code, nanoPost has a step-by-step guide to WordPress SMTP without a plugin. This approach uses PHPMailer’s phpmailer_init action hook and stores credentials in wp-config.php. It works, but foregoes the logging and diagnostic features that a dedicated plugin provides.
Authenticating your sending domain (SPF, DKIM, DMARC)
Connecting to an external service gets messages delivered. Authenticating the sending domain gets them delivered to the inbox rather than the spam folder.
Email authentication works through DNS records that tell receiving servers which infrastructure is authorised to send mail for a domain. Three standards matter: SPF (which IP addresses may send for this domain), DKIM (a cryptographic signature proving the message was sent by an authorised system and was not modified in transit), and DMARC (the policy that tells receiving servers what to do when SPF or DKIM checks fail, plus aggregate reporting back to the domain owner).
nanoPost’s DNS setup guide for WordPress email covers the syntax and configuration of each record type in detail. What catches people in practice is not the initial setup (most providers generate the exact TXT records to copy into DNS) but the merge step. SPF requires exactly one record per domain. A site that already has an SPF record for Google Workspace and adds a second record for Brevo ends up with two SPF records, and RFC 7208, section 3.2 prohibits multiple records that would cause an authorization check to select more than one. The result is a PermError: SPF evaluation fails, and receiving servers treat the domain as unauthenticated. The fix is to merge the include: directives into a single record:
v=spf1 include:_spf.google.com include:sendinblue.com ~all
This is the single most common DNS authentication mistake nanoPost encounters. The domain owner often doesn’t notice. There is no bounced email, no error message in WordPress. Messages just land in spam, and the PermError is visible only in the receiving server’s authentication results.
Contact forms and the database safeguard
Contact form plugins (Contact Form 7, WPForms, Gravity Forms, Fluent Forms, Ninja Forms) all send submissions through wp_mail(), so the external service and mailer plugin handle their delivery automatically. The one safeguard worth adding: store submissions in the WordPress database, not only in email. If email delivery fails for any reason (a misconfigured service, an expired API key, a DNS change), the submissions are still accessible. Some contact form plugins store submissions natively. For Contact Form 7, the
Flamingo plugin adds this capability. nanoPost’s contact form comparison covers storage features across the field.
Verifying the setup
All three mailer plugins named above include a “Send Test Email” function in their settings. Use it. When the test message arrives, check the headers. Look for spf=pass and dkim=pass in the Authentication-Results header. If either shows fail or none, the DNS records need attention before going further.
For a more thorough check, nanoPost’s email test suite walks through testing every category of WordPress-generated email: password resets, new-user notifications, WooCommerce order emails, and form submissions. Running even two or three of these tests confirms that the mailer plugin is intercepting wp_mail() correctly across different calling contexts.
If something fails: nanoPost’s WordPress email troubleshooting guide covers the common failure modes: plugin conflicts, incorrect SMTP credentials, port blocking, PHP version incompatibilities, and DNS propagation delays. For ongoing monitoring, an email logging plugin records every message WordPress sends (or fails to send), making intermittent delivery problems visible.
Reference links
- SMTP email services compared
- WordPress mailer plugins compared
- SPF, DKIM, DMARC setup guide
- Email test suite
- WordPress email troubleshooting
- WordPress SMTP without a plugin
- Contact form plugins compared
Provider details (free-tier allowances, port-blocking policies) last verified June 2026.

