WordPress SMTP: sending email via an external mail provider

WordPress hands every email to PHP's mail() function, which most hosts either block or ship from an unauthenticated IP. This walkthrough sets up an SMTP plugin that routes WordPress mail through a real sending service that actually delivers.

Goal

By the end of this walkthrough you will have a WordPress site that routes every outgoing message, including contact form notifications, password resets and WooCommerce order confirmations, through an authenticated SMTP or API connection to an external mail provider. You will have verified delivery with a real test email, and you will know where to look in the plugin's log when something breaks later.

Prerequisites

  • Administrator access to WordPress at /wp-admin/.
  • Ability to install plugins (shared hosting and managed WordPress plans both qualify).
  • An account on one sending provider. This article covers Gmail (free, limited volume), SendGrid, Mailgun, Amazon SES and Postmark. Pick one before you start.
  • Access to your domain's DNS zone (your registrar or your DNS provider's control panel). You will need it to publish SPF and DKIM records.
  • A real mailbox on the domain you send from, for example noreply@yoursite.nl. Do not send "from" wordpress@yoursite.nl or the gmail address of the admin. The WordPress wp_mail_from documentation states: "To avoid your email being marked as spam, it is highly recommended that your from domain match your website."

If WordPress is currently not sending any mail at all, work through why WordPress is not sending email and how to fix it first to confirm the problem is at the transport layer. This article assumes the underlying site and PHP environment are healthy; what you need is a better transport.

Why WordPress emails go missing in the first place

By default, wp_mail() hands every message to PHPMailer with no transport configured, which means PHPMailer falls through to PHP's mail() function. PHP mail() writes the message to a local sendmail-compatible binary on the server, which then tries to relay the message straight to the recipient's mail server on port 25.

Three things routinely go wrong with that path:

  1. Port 25 is blocked. Virtually every shared host and every major cloud provider blocks outbound port 25 for their customer VMs to prevent spam origination. RFC 5321 defines port 25 for server-to-server relay, not for client submission; client submission belongs on port 587 with STARTTLS or port 465 with implicit TLS. If port 25 is blocked, your message never leaves the host.
  2. The message has no authentication. PHP mail() sends with no SPF alignment, no DKIM signature and no DMARC-compliant From header. Since Google's sender guidelines took effect in February 2024, unauthenticated mail to Gmail addresses is rejected or junked. Outlook and Yahoo apply similar rules.
  3. wp_mail() returns true anyway. PHPMailer considers the message "sent" the moment the local MTA accepts it, regardless of whether anything downstream delivers it. That is why the symptom is silence, not an error.

The fix is to stop using PHP mail() entirely. A WordPress SMTP plugin hooks into WordPress through the pre_wp_mail filter (WordPress 5.7.0) or the older phpmailer_init action (WordPress 2.2.0) and swaps the default mailer for an authenticated connection to a real sending service. WordPress still calls wp_mail() everywhere; the plugin just intercepts the call before it reaches PHP mail().

Which plugin: FluentSMTP, WP Mail SMTP or Post SMTP

All three do the same core job. The practical differences come down to what is free:

Plugin Free logging Free multi-provider routing Free Amazon SES Notes
FluentSMTP Yes Yes Yes Strongest free tier. Route different email types through different providers without a Pro upgrade.
WP Mail SMTP Only in Pro Only in Pro Only in Pro Largest install base. Very readable setup wizard for first-time users.
Post SMTP Yes Limited Yes Real-time failure alerts (Slack, Teams, SMS) and a backup SMTP path.

I recommend FluentSMTP for almost every case. The free logging alone pays for itself the first time a client reports "I never got an email." The walkthrough below uses FluentSMTP; the concepts map one-for-one onto WP Mail SMTP and Post SMTP, only the screen layout differs.

Provider walkthrough 1: Gmail (personal account or Google Workspace)

Gmail is the quickest path if you already have a Google account, but it comes with two hard caps: Google Workspace limits outbound to 2,000 messages per 24 hours and personal Gmail limits to 500 unique recipients per 24 hours. It is fine for a small business site; it is not fine for WooCommerce on a busy day.

Before you start: what changed with Google in 2024 and 2025

Google phased out basic password authentication (the "Less Secure Apps" setting) over several stages, with the final cutoff on March 14, 2025. After that date, your normal Google account password will not authenticate SMTP at all, on any account type.

Two paths still work:

  • OAuth2 via FluentSMTP's dedicated Gmail/Google Workspace connection. Most robust; no passwords stored in WordPress.
  • App Passwords, which are 16-character tokens generated specifically for third-party apps. Google's own transition document explicitly preserves them: "You will no longer use a password for access (with the exception of app passwords)." App Passwords require 2-Step Verification on the Google account.

Both are still supported. Pick OAuth2 if you can give the plugin redirect permissions on the Google account; pick App Passwords if the account has 2FA and you want to avoid OAuth plumbing.

  1. In WordPress: go to Plugins > Add New, search for FluentSMTP, install and activate.
  2. Open Settings > FluentSMTP > Connections and click Add Another Connection.
  3. Select Gmail / Google Workspace.
  4. Enter the From Email (the real mailbox you want WordPress to send from, for example noreply@yoursite.nl) and the From Name.
  5. In a new tab, open the Google Cloud Console, create a new project, enable the Gmail API, create an OAuth client ID of type Web application, and add https://yoursite.nl/wp-admin/options-general.php?page=fluent-mail as the Authorized redirect URI. Copy the Client ID and Client Secret.
  6. Back in FluentSMTP, paste the Client ID and Client Secret and click Authorize. Sign in with the Google account you want to send from and grant the requested scopes.
  7. Click Save Connection Settings.

Expected result: the Connections tab shows a new row with provider "Gmail" and the connected account address. Go to Test Email, send a message to a different mailbox, and confirm it arrives with a valid DKIM signature (see the verification section below).

Setup with an App Password

  1. In Google, enable 2-Step Verification on the account if it is not already on.
  2. Visit myaccount.google.com/apppasswords and generate an App Password. Name it something like FluentSMTP yoursite.nl. Google will show you a 16-character token like abcd efgh ijkl mnop. Copy it without spaces.
  3. In WordPress, open Settings > FluentSMTP > Connections and click Add Another Connection.
  4. Select Other SMTP.
  5. Fill in:
    • SMTP Host: smtp.gmail.com
    • SMTP Port: 587
    • Encryption: TLS
    • Auto TLS: on
    • Authentication: on
    • SMTP Username: your full Gmail or Workspace address
    • SMTP Password: the 16-character App Password you just generated
  6. Click Save Connection Settings.

Expected result: the Connections tab lists a new SMTP row pointing at smtp.gmail.com:587. If saving fails with an authentication error, the most common cause is a typo in the App Password or 2FA not being enabled on the account.

Provider walkthrough 2: SendGrid, Mailgun, Amazon SES or Postmark

For any volume beyond a handful of transactional messages per day, a dedicated sending service is the right answer. These providers handle domain authentication, bounce processing, reputation monitoring and deliverability on your behalf. Each has an SMTP path and, in most cases, an API path. FluentSMTP connects to both.

Pick one before you start

Provider Free tier (approx.) Strengths
SendGrid 100/day forever Well-documented, large ecosystem, bulk-email-friendly.
Mailgun Pay-as-you-go from about 1,000/month Developer-friendly API, strong logging.
Amazon SES Very low cost after the first 62,000/month from EC2 Cheapest at scale, starts in sandbox mode.
Postmark Trial only, paid from day one Best-in-class deliverability for pure transactional mail.

Setup with SendGrid (SMTP mode)

  1. Sign up at sendgrid.com and complete the sender authentication wizard for the domain you send from. This publishes the CNAME records SendGrid needs to DKIM-sign on your behalf.
  2. In SendGrid, go to Settings > API Keys and create a key with the Mail Send permission. Copy the key (it starts with SG.); you will not be able to view it again.
  3. In WordPress, open FluentSMTP > Add Another Connection and select SendGrid.
  4. Enter your API key and the verified From Email and From Name.
  5. Click Save Connection Settings.

Expected result: a new connection row with provider "SendGrid". FluentSMTP will call the SendGrid REST API; no SMTP port needs to be open from your host.

Setup with Mailgun

  1. Sign up at mailgun.com and add a sending domain. Mailgun will give you four DNS records (SPF include, DKIM CNAME or TXT, and optional tracking CNAMEs). Publish all of them in your DNS zone.
  2. Wait for Mailgun to verify the records (usually 10 to 30 minutes). The domain must show as Verified before mail will deliver.
  3. Go to Sending > Domain settings > API keys and copy the Private API key.
  4. In WordPress, open FluentSMTP > Add Another Connection and select Mailgun.
  5. Enter the API key, the sending domain and the region (US or EU). Getting the region wrong is a classic first-time mistake: Mailgun EU accounts cannot authenticate against the US API endpoint.
  6. Save.

Expected result: a new Mailgun connection row. Send a test email; FluentSMTP should report a 200 response from the Mailgun API.

Setup with Amazon SES

  1. In AWS, enable Amazon SES in the region closest to your site.
  2. Verify your sending domain by publishing the DKIM CNAMEs and the SPF include that SES gives you. Verify the individual sender address too if SES asks for it.
  3. Move out of the SES sandbox. By default, new SES accounts are in sandbox mode, which limits you to 200 messages per 24 hours and only allows sending to verified recipient addresses. Open a production access request from Account dashboard > Request production access and provide a short description of your use case. Approval usually takes a business day.
  4. Create an IAM user with the AmazonSESFullAccess policy (or a scoped-down equivalent), generate an access key ID and secret access key, and copy both.
  5. In WordPress, open FluentSMTP > Add Another Connection and select Amazon SES.
  6. Enter the access key, secret key and region. Save.

Expected result: a new Amazon SES connection row. Send a test. If you are still in sandbox mode and sending to an unverified address, SES will reject with MessageRejected: Email address is not verified; that is the signal you still need production access.

Setup with Postmark

  1. Sign up at postmarkapp.com and create a server for your site (Postmark groups streams under servers).
  2. Add your sending domain and publish the DKIM TXT record and the optional Return-Path CNAME that Postmark provides.
  3. Copy the Server API Token from the server's API Tokens tab.
  4. In WordPress, open FluentSMTP > Add Another Connection and select Postmark.
  5. Enter the Server API Token and the verified From Email.
  6. Save.

Expected result: a new Postmark connection row. Postmark's SMTP reference documents ports 25, 2525 and 587 with STARTTLS if you ever need to fall back to raw SMTP. In FluentSMTP you do not need to touch ports; the plugin uses the API.

Verify that WordPress actually delivers mail

A plugin that saves without errors is not the same as a plugin that delivers. Run this verification every time you change provider.

Step 1: send a test from FluentSMTP

  1. Open Settings > FluentSMTP > Test Email.
  2. Enter a destination address on a different domain than your WordPress site, ideally a Gmail inbox you control.
  3. Leave the default connection selected.
  4. Click Send Test Email.

Expected output: a green "Success" banner at the top of the page.

Step 2: inspect the delivered message in the recipient inbox

Open the test email in the Gmail inbox you sent it to, click the three-dot menu next to the sender and pick Show original. Gmail will display the full headers and, at the top, an Authentication-Results block.

You want to see all three passing:

Authentication-Results: mx.google.com;
       dkim=pass header.i=@yoursite.nl ...
       spf=pass (google.com: domain of bounce@yoursite.nl ...) ;
       dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=yoursite.nl

If DKIM says fail or none, the sending provider's DKIM CNAMEs are not published correctly in your DNS zone. If SPF says softfail, the provider's SPF include is missing. If DMARC says fail, the From domain is not aligned with the authenticated domain; change the From address in FluentSMTP to a mailbox on the same domain that signed the DKIM.

Step 3: trigger a real WordPress mail and confirm it also delivers

The test email path proves the plugin connection works. A real wp_mail() call proves that WordPress itself is routing through the plugin. Do one of:

  • Request a password reset for your own admin user at /wp-login.php?action=lostpassword.
  • Submit a test contact form.
  • Place a test WooCommerce order.

Then check:

  1. The message arrives in the expected inbox.
  2. The FluentSMTP log (Email Logs tab) shows the send, with status "Sent".
  3. The From address matches what you configured, not wordpress@yoursite.nl.

If the test email from Step 1 works but a password reset does not arrive, something in WordPress is short-circuiting wp_mail() before FluentSMTP sees it. Disable other mail-related plugins (security plugins, older SMTP plugins you forgot to uninstall) and try again. For the broader diagnosis of password reset failures on WordPress, including causes that have nothing to do with SMTP, see password reset not working in WordPress.

Read the email logs when things break later

FluentSMTP's Email Logs tab is the single most useful debugging surface on this plugin. Keep it enabled.

What to look for when a user reports "I never got the email":

  • The log row exists. If it exists, WordPress did call wp_mail(). The problem is on the delivery side: bounce, spam placement or recipient-side filtering.
  • The log row is missing entirely. WordPress never called wp_mail(). Look upstream at the plugin or page that was supposed to trigger it.
  • Status is "Failed". FluentSMTP captured a provider error. Click the row to see the provider response. Common causes: expired API key, DNS records removed from the zone, or the sender address changed to something the provider has not verified.

For sites that handle real money (WooCommerce, membership plugins), I also hook wp_mail_failed into a must-use plugin so failures go to wp-content/debug.log as well as into FluentSMTP's log. Use your hosting panel's file manager (or an SFTP client) to create the file wp-content/mu-plugins/log-mail-errors.php with the following contents. If the mu-plugins folder does not exist yet, create it first inside wp-content:

<?php
// Logs every wp_mail() failure to wp-content/debug.log
add_action( 'wp_mail_failed', function ( WP_Error $error ) {
    error_log( 'wp_mail_failed: ' . $error->get_error_message() );
    error_log( print_r( $error->get_error_data(), true ) );
} );

wp_mail_failed was added in WordPress 4.4.0 and fires whenever PHPMailer throws. It catches failures that happen before the plugin logs them.

Authenticate your sending domain with SPF, DKIM and DMARC

SMTP gets the message to the provider. Domain authentication gets the provider's message accepted by Gmail, Outlook and Yahoo. Since Google's bulk sender rules took effect on February 1, 2024, the practical baseline for any WordPress site is SPF + DKIM + DMARC on the sending domain, regardless of volume.

Every provider in the walkthroughs above gives you the exact records to publish. At a minimum you will add:

  1. One SPF TXT record on the sending domain (root). Typically something like v=spf1 include:sendgrid.net include:_spf.google.com -all. Only one SPF record is allowed per domain; merge includes into a single record if you use multiple providers.
  2. One or more DKIM records (usually CNAME or TXT) on a provider-specific selector, for example s1._domainkey.yoursite.nl. The provider's dashboard gives you the exact names and values.
  3. One DMARC TXT record at _dmarc.yoursite.nl, starting with v=DMARC1; p=none; rua=mailto:dmarc@yoursite.nl. p=none is monitor-only; once DMARC reports confirm legitimate mail is passing for a couple of weeks, raise the policy to p=quarantine and then p=reject.

A deeper walkthrough of the three records, including how to merge multiple SPF includes and how to interpret DMARC reports, is covered in the full SPF, DKIM and DMARC walkthrough for WordPress; until then, start with the values your provider gives you and verify with the Gmail "Show original" header check above.

WooCommerce and other plugins: nothing extra to configure

WooCommerce sends every transactional email (new order, completed order, customer invoice, password reset, refund notice) via wp_mail(). The WooCommerce documentation states it bluntly: "WooCommerce triggers the wp_mail() function. This function signals WordPress to process the email. However, since WordPress isn't an email server, it delegates this task to PHP."

That means the moment you configure FluentSMTP (or any other WordPress SMTP plugin) at the WordPress level, WooCommerce emails immediately start flowing through the same path. You do not configure WooCommerce separately. The same holds for Contact Form 7, Gravity Forms, Fluent Forms, WPForms, BuddyPress, LearnDash and every other plugin that uses wp_mail(): they all inherit the transport you just configured.

The only exception is plugins that bypass wp_mail() on purpose, usually by calling PHPMailer directly or by sending via cURL to an external API. Those are rare and usually documented as such. If you suspect one, check the plugin's settings for a separate "email" or "SMTP" section.

Final configuration checklist

Before you consider this done:

  • [ ] FluentSMTP installed, active and set as the primary connection.
  • [ ] From address is a real mailbox on your own domain, monitored by a human or routed to one.
  • [ ] Test email from FluentSMTP > Test Email arrives in an external inbox and passes SPF, DKIM and DMARC in Gmail's "Show original" view.
  • [ ] A real WordPress email (password reset, contact form, WooCommerce order) arrives and shows up in FluentSMTP's Email Logs with status "Sent".
  • [ ] SPF, DKIM and DMARC records are published in DNS for the sending domain.
  • [ ] Email Logs retention is set to 30 to 90 days, long enough to investigate a late complaint but short enough to avoid storing sensitive message bodies forever.
  • [ ] The wp_mail_failed mu-plugin is in place on revenue-critical sites.

If anything on that list fails, go back to the Verify section above and work through it in order. The most common failure is DKIM: the provider issued the keys, you copied the CNAMEs, but your DNS provider silently dropped the trailing dot or wrapped the value in quotes. Use your DNS provider's control panel to double-check the published records, or verify with an online tool like MXToolbox DKIM Lookup. If you have SSH access: run dig CNAME s1._domainkey.yoursite.nl to confirm the record resolves before assuming the plugin is wrong.

Need professional email without the hassle?

Email on your own domain with spam filtering and personal setup help. No Microsoft 365 or Google Workspace overhead.

Explore email hosting

Search this site

Start typing to search, or browse the knowledge base and blog.