Password resets don’t arrive. Contact form messages vanish. WooCommerce order emails land in spam. These are some of the most common WordPress problems on a fresh VPS. The reason is simple: by default, WordPress hands email to PHP’s mail() function, which needs a working mail server on the machine, and even then messages from a random server IP rarely reach the inbox.

Why WordPress email fails

  • No MTA installed: mail() has nothing to pass the message to, so it fails silently.
  • Outbound port 25 blocked: many providers block it by default to prevent spam.
  • No authentication: messages without SPF, DKIM and DMARC alignment go to spam, or get rejected.
  • “From” address mismatch: sending as [email protected] from a server that isn’t authorised for that domain.
  • IP reputation: a new VPS IP has no sending history.

Instead of mail(), make WordPress authenticate to a proper mail service over SMTP (port 587 or 465):

  1. Choose a sending service:
    • Transactional email services (Amazon SES, Postmark, Mailgun, SendGrid, Brevo, and others): best deliverability, good logs. See transactional email services.
    • Your business mailbox (Google Workspace, Microsoft 365, Zoho): fine for low volume, with sending limits.
  2. Install an SMTP plugin: WP Mail SMTP, FluentSMTP, Post SMTP, or a service’s own plugin. Many support API sending (HTTPS) as well as SMTP.
  3. Configure: host, port 587 (STARTTLS) or 465 (TLS), username and password (or API key), and the From email on your own domain.
  4. Verify your domain with the service, and add its SPF and DKIM DNS records, plus a DMARC record.
  5. Send a test email from the plugin, and check it arrives in the inbox, not spam.

See SMTP ports 25, 465 and 587 and SPF, DKIM and DMARC.

Store credentials outside the database if your plugin supports it (constants in wp-config.php), so they don’t end up in database dumps.

Example: WP Mail SMTP with constants

// wp-config.php
define( 'WPMS_ON', true );
define( 'WPMS_MAIL_FROM', '[email protected]' );
define( 'WPMS_MAIL_FROM_NAME', 'Example Shop' );
define( 'WPMS_MAILER', 'smtp' );
define( 'WPMS_SMTP_HOST', 'smtp.example-provider.com' );
define( 'WPMS_SMTP_PORT', 587 );
define( 'WPMS_SSL', 'tls' );
define( 'WPMS_SMTP_AUTH', true );
define( 'WPMS_SMTP_USER', 'apikey-or-username' );
define( 'WPMS_SMTP_PASS', 'secret' );

(Constant names differ between plugins. Check your plugin’s documentation.)

Alternative: send directly from your VPS

You can run a mail transfer agent (Postfix) and send directly, but only if:

  • outbound port 25 is open at your provider;
  • the server IP has a PTR (reverse DNS) record matching your mail hostname;
  • SPF, DKIM (OpenDKIM) and DMARC are configured;
  • you monitor blocklists and bounces.

On VPS.DO, outbound mail and PTR records are available on USA VPS plans (you can set PTR in the client area). For most WordPress sites, an SMTP relay service is still easier and more reliable. See Postfix and Dovecot and email VPS.

A middle ground: Postfix as a local relay (smarthost) to your SMTP service, which also covers cron mail and other apps on the server.

Test and troubleshoot

# send a test from WordPress via WP-CLI
wp eval 'var_dump( wp_mail( "[email protected]", "Test", "Hello from WordPress" ) );'
  • bool(false): the mail call failed. Check the SMTP plugin’s debug log, and whether outbound ports 587/465 are reachable: nc -vz smtp.example-provider.com 587.
  • Delivered, but to spam: check SPF, DKIM and DMARC alignment (use an online mail tester), and that the “From” domain matches the authenticated domain.
  • Log all outgoing emails (most SMTP plugins can), so you can see what WordPress tried to send.

WooCommerce and forms

  • WooCommerce order emails use wp_mail(), so the same SMTP setup fixes them.
  • Contact form plugins: set the From address to your own domain, and put the visitor’s address in Reply-To. Using the visitor’s address as From fails DMARC.

Quick reference

Problem Fix
No emails at all Install an SMTP plugin + sending service
Emails in spam SPF, DKIM, DMARC; From address on your domain
Port 25 blocked Use 587/465 to an SMTP service
Test wp eval 'var_dump(wp_mail(...));'
Visibility Enable email logging in the SMTP plugin

Related: email deliverability and WordPress VPS hosting.

  • WordPress
  • Email
  • SMTP