Docs / WordPress

Send email in WordPress over SMTP

WordPress sends every notification — password resets, new user registrations, comment alerts, contact form submissions, WooCommerce order confirmations — through one function, wp_mail(). Out of the box that function hands the message to PHP's mail(), which is why so many WordPress sites find their email silently disappearing or landing in spam. This guide routes wp_mail() through Postwing's authenticated SMTP relay instead.

Why WordPress emails do not arrive

There are two separate failures, and both are fixed by the same change:

  • Nothing is listening. PHP's mail() shells out to a local sendmail binary. Most managed and cloud hosting ships without a local mail server, so the call succeeds, wp_mail() returns true, and the message is discarded.
  • Nothing is authenticated. Where a local server does exist, the message leaves with no DKIM signature and from an IP that your domain's SPF record does not list. Gmail and Outlook treat that as forgery — it is filtered as spam or rejected outright.

Sending over an authenticated SMTP relay solves both: the relay signs each message with DKIM for your verified domain, and it sends from IPs your SPF record already covers, so DMARC aligns.

You can get them on the token management page. For security reasons, a token is shown only once — at the moment it is created.

SMTP connection settings

SettingValue
SMTP hostsmtp.postwing.app
Port587
EncryptionSTARTTLS (the connection is upgraded to TLS before login)
UsernameThe login of an SMTP token for your domain
PasswordThe password of that token — shown once, when the token is created
Every mode is also available on a high port: 8465 (SSL/TLS), 8587 (STARTTLS) and 8025 (plain). Many hosting providers and clouds block outbound 25, 465 and 587 — if the connection times out, switch to the matching high port.

Method 1 — WP Mail SMTP (recommended)

WP Mail SMTP is the most widely used option and has a built-in connection test. Install it from Plugins → Add New, then open WP Mail SMTP → Settings and fill in:

FieldValue
From Emailnoreply@your-domain.com — must be on your verified domain
Force From EmailOn — stops other plugins overriding the sender
From NameYour site name
MailerOther SMTP
SMTP Hostsmtp.postwing.app
EncryptionTLS (this is STARTTLS, despite the label)
SMTP Port587
Auto TLSOn
AuthenticationOn
SMTP UsernameThe login of an SMTP token for your domain
SMTP PasswordThat token's password

Then open the Email Test tab, send a message to yourself and confirm it arrives.

Keep the password out of the database

Entered through the settings screen, the SMTP password is stored in the WordPress database in recoverable form. Define it in wp-config.php instead — WP Mail SMTP reads these constants and greys the corresponding fields out in the UI:

wp-config.php
/* Add ABOVE the "That's all, stop editing!" line in wp-config.php */

define( 'WPMS_ON', true );                       // let constants override the UI
define( 'WPMS_MAILER', 'smtp' );

define( 'WPMS_SMTP_HOST', 'smtp.postwing.app' );
define( 'WPMS_SMTP_PORT', 587 );
define( 'WPMS_SSL', 'tls' );                     // 'tls' = STARTTLS, 'ssl' = port 465
define( 'WPMS_SMTP_AUTH', true );
define( 'WPMS_SMTP_USER', 'token-login@your-domain.com' );
define( 'WPMS_SMTP_PASS', 'your-token-password' );

define( 'WPMS_MAIL_FROM', 'noreply@your-domain.com' );
define( 'WPMS_MAIL_FROM_NAME', 'Your Site' );
define( 'WPMS_MAIL_FROM_FORCE', true );          // override plugins that set their own From

Method 2 — FluentSMTP

FluentSMTP is free with no paid tier and supports fallback connections. Go to Settings → FluentSMTP → Add Another Connection, pick Other SMTP, and enter the same host, port 587, TLS encryption and your token credentials. Tick Store password in wp-config.php file so it is written there rather than to the database.

WP Mail SMTP, FluentSMTP and Post SMTP all hook phpmailer_init. With two active, whichever runs last wins and the behaviour depends on plugin load order — which looks exactly like an intermittent delivery bug. Deactivate the others before adding one.

Method 3 — no plugin

WordPress exposes the underlying PHPMailer instance through the phpmailer_init action, so a small must-use plugin is all you need. This avoids a plugin update ever silently changing your mail setup:

wp-content/mu-plugins/smtp-mailer.php
<?php
/**
 * Plugin Name: SMTP for wp_mail
 * Description: Routes every wp_mail() call through an authenticated SMTP relay.
 *
 * Save as wp-content/mu-plugins/smtp-mailer.php — mu-plugins load automatically
 * and cannot be deactivated by accident from the admin.
 */

add_action( 'phpmailer_init', function ( $phpmailer ) {
    $phpmailer->isSMTP();
    $phpmailer->Host       = 'smtp.postwing.app';
    $phpmailer->Port       = 587;
    $phpmailer->SMTPSecure = 'tls';       // STARTTLS; use 'ssl' with port 465
    $phpmailer->SMTPAuth   = true;
    $phpmailer->Username   = SMTP_USER;   // defined in wp-config.php
    $phpmailer->Password   = SMTP_PASS;
    $phpmailer->Timeout    = 10;
} );

// Send as your own domain, not as wordpress@your-server-hostname
add_filter( 'wp_mail_from', fn() => 'noreply@your-domain.com' );
add_filter( 'wp_mail_from_name', fn() => 'Your Site' );

Define SMTP_USER and SMTP_PASS in wp-config.php alongside it.

Test the configuration

Each plugin has its own test button, but WP-CLI exercises the real wp_mail() path, which is what your themes and plugins actually call:

bash
# Send a test message straight through wp_mail()
wp eval "var_dump( wp_mail( 'you@example.com', 'SMTP test', 'It works.' ) );"

# Show the underlying error if it returns false
wp eval "add_action('wp_mail_failed', fn(\$e) => print_r(\$e->get_error_message())); wp_mail('you@example.com','SMTP test','It works.');"

If it fails, log the full SMTP conversation temporarily:

php
// Temporarily log the SMTP conversation to debug a failing connection.
add_action( 'phpmailer_init', function ( $phpmailer ) {
    $phpmailer->SMTPDebug   = 2;
    $phpmailer->Debugoutput = 'error_log';
}, 100 );
SMTPDebug writes the entire session — including the authentication exchange — to your PHP error log. Remove it as soon as the connection works.

Troubleshooting

SymptomCause and fix
SMTP connect() failed Host blocks outbound mail ports. Change the port to 8587 (TLS) or 8465 (SSL).
SMTP Error: Could not authenticate Wrong token login or password, or Authentication is switched off in the plugin.
Test email works, contact form does not The form plugin sets its own From address. Enable Force From Email.
Mail arrives but goes to spam The From address is not on your verified domain — check it is not wordpress@… plus your server hostname.
Settings look right but nothing changed A second SMTP plugin is active, or a caching plugin is serving a stale wp-config.php opcache entry.
550 sender rejected The From domain is not verified, or the token does not cover it.

Frequently asked questions

Why is WordPress not sending emails at all?

By default wp_mail() hands the message to PHP's mail() function, which passes it to a local sendmail binary. On most modern hosting there is no mail server behind it, so nothing is ever delivered. Even where one exists, the message is unauthenticated and fails SPF, DKIM and DMARC checks at the recipient. Routing wp_mail() through an authenticated SMTP relay fixes both problems.

Which WordPress SMTP plugin should I use?

WP Mail SMTP is the most widely installed and has the clearest setup wizard. FluentSMTP is fully free with no paid tier and adds fallback connections. Post SMTP is a good third option with detailed logging. Any of them work — pick one and only one, because two SMTP plugins active at once will fight over the phpmailer_init hook.

Should I use port 587 or 465 in WP Mail SMTP?

Use 587 with the encryption set to TLS, which means STARTTLS. Choose SSL only with port 465. Mismatching the two — SSL on 587 or TLS on 465 — is the most common cause of the plugin's connection test failing.

Why do WordPress emails still go to spam after setting up SMTP?

Usually because the From address is not on the domain you authenticated. If WordPress sends as wordpress@your-server.hosting-provider.com while your DKIM and SPF records are on your-domain.com, nothing aligns and DMARC fails. Set the From address to something on your verified domain and enable the plugin's Force From Email option.

Is it safe to store the SMTP password in wp-config.php?

It is safer than the plugin's settings screen, which stores the password in the database where a database dump or a compromised admin account exposes it. wp-config.php sits outside the database and is not served by the web server. Best of all is to keep the constant's value in an environment variable your host provides.

Can I send WordPress email over SMTP without a plugin?

Yes. WordPress fires the phpmailer_init action before every send, so a small must-use plugin that sets the PHPMailer instance to SMTP mode is enough. It avoids a plugin update ever changing your mail configuration, at the cost of no admin UI, no test button and no logging.

Why does the connection time out on my host?

Many shared hosts block outbound connections on ports 25, 465 and 587 to limit spam from compromised sites. Switch the port to 8587 for STARTTLS or 8465 for SSL and the connection will establish.

Next steps