WordPress

How to configure WordPress SMTP without plugin

23 Mar 2018By Ivan5 min read
How to configure WordPress SMTP without plugin

TL;DR: You don’t need a plugin to send WordPress email over SMTP. Define SMTP creds in wp-config.php and hook phpmailer_init in your theme (or a small “must-use” mu-plugin) to configure PHPMailer. Test with wp_mail() or WP-CLI.

Why do this?

  • Reliability: Many hosts block mail() or throttle it. SMTP via your transactional provider (Postmark, SendGrid, Mailgun, SES, etc.) is far more deliverable.
  • Security & control: Keep credentials outside the DB, version your code, and avoid plugin bloat.
  • Portability: Same approach works on shared hosts, VPS, and containers.

Assumptions: You’re comfortable editing theme files / mu-plugins and have SMTP credentials from a provider. Tested on modern WordPress 6.x.

Step 1 – Put SMTP secrets in wp-config.php

Add constants so code doesn’t hardcode secrets.

// wp-config.php

define('SMTP_HOST',    'smtp.example.com');
define('SMTP_PORT',    587);
define('SMTP_USER',    '[email protected]');
define('SMTP_PASS',    'super-secret-password');
define('SMTP_SECURE',  'tls'); // 'tls' or 'ssl' or '' (empty for none)
define('SMTP_AUTH',    true);
define('SMTP_FROM',    '[email protected]');
define('SMTP_NAME',    'Example Site');

Step 2 – Configure PHPMailer via phpmailer_init

Add this to your theme’s functions.php, a small site-specific plugin, or better a file in wp-content/mu-plugins/ (loads on every request, independent of theme).

<?php
// wp-content/mu-plugins/smtp.php (create the /mu-plugins dir if needed)

add_action('phpmailer_init', function ($phpmailer) {
    // Force SMTP
    $phpmailer->isSMTP();

    // Core SMTP settings
    $phpmailer->Host       = defined('SMTP_HOST') ? SMTP_HOST : 'localhost';
    $phpmailer->Port       = defined('SMTP_PORT') ? (int)SMTP_PORT : 25;
    $phpmailer->SMTPAuth   = defined('SMTP_AUTH') ? (bool)SMTP_AUTH : false;
    $phpmailer->Username   = defined('SMTP_USER') ? SMTP_USER : '';
    $phpmailer->Password   = defined('SMTP_PASS') ? SMTP_PASS : '';

    // Encryption: 'tls', 'ssl', or '' (none)
    $phpmailer->SMTPSecure = defined('SMTP_SECURE') ? SMTP_SECURE : '';

    // Avoid STARTTLS surprises when no encryption is set
    if (empty($phpmailer->SMTPSecure)) {
        $phpmailer->SMTPAutoTLS = false;
    }

    // From headers (fallbacks if constants not defined)
    $phpmailer->setFrom(
        defined('SMTP_FROM') ? SMTP_FROM : get_bloginfo('admin_email'),
        defined('SMTP_NAME') ? SMTP_NAME : get_bloginfo('name'),
        false // don't override Reply-To automatically
    );
});

// (Optional) Keep WP filters in sync with your From headers
add_filter('wp_mail_from', function ($email) {
    return defined('SMTP_FROM') ? SMTP_FROM : $email;
});

add_filter('wp_mail_from_name', function ($name) {
    return defined('SMTP_NAME') ? SMTP_NAME : $name;
});

That’s it. Every wp_mail() call now uses your SMTP server.

Step 3 – Test it

Quick PHP test inside WordPress

Create a temporary admin-only route or use a throwaway snippet:

wp_mail(
  get_option('admin_email'),
  'SMTP test from ' . get_bloginfo('name'),
  "If you're reading this, SMTP is configured.\n\nTime: " . wp_date('c')
);

WP-CLI (preferred)

# From your WP root
wp eval "var_dump( wp_mail( '[email protected]', 'SMTP test', 'Hello from WP-CLI' ) );"

If it returns bool(true) and you receive the email, you’re good.

Common provider examples

Replace host, ports, and security according to your provider’s docs.

SendGrid / Mailgun / Postmark (SMTP):

  • Host: provided by vendor (e.g., smtp.sendgrid.net)
  • Port: 587 (TLS) or 465 (SSL)
  • Secure: tls or ssl
  • Auth: true
  • Username/Password: API key pattern per vendor

Amazon SES (SMTP):

  • Host: email-smtp.<region>.amazonaws.com
  • Port: 587 (TLS) or 465 (SSL)
  • Username/Password: SES SMTP credentials (generated in console)

Gmail / Google Workspace (less ideal for production):

  • Host: smtp.gmail.com
  • Port: 587 (TLS)
  • Use an App Password (2FA required), not your account password.

Troubleshooting & gotchas

  • “Connection timed out / refused”
    Your host may block outbound SMTP ports (25/587/465). Open a ticket or proxy through a supported port.
  • STARTTLS errors when SMTPSecure is empty
    Set $phpmailer->SMTPAutoTLS = false; as shown to avoid opportunistic TLS if your server doesn’t advertise it correctly.
  • Mixed “From” behavior
    Some providers (e.g., SES) require sending from a verified domain. Use SMTP_FROM with a verified address.
  • Multiple hooks fighting
    Other plugins may also hook phpmailer_init. Move your code to mu-plugins to run early and ensure your settings win, or add priorities.
  • Don’t log secrets
    If you temporarily enable debugging: add_action('phpmailer_init', function ($phpmailer) { $phpmailer->SMTPDebug = 2; // verbose to error_log $phpmailer->Debugoutput = static function ($str, $level) { error_log("SMTP[$level] $str"); }; }, 20); Remove this in production and never dump usernames or passwords.
  • Credential storage
    Keep secrets in wp-config.php outside version control. Avoid committing them.

When a plugin still makes sense

If non-technical admins must switch providers, track deliverability, or add per-recipient routing, a reputable SMTP plugin provides a GUI and health checks. For lean, developer-run sites, the lightweight code approach above is faster and safer.

Full minimal snippet (copy-paste)

wp-config.php

define('SMTP_HOST',   'smtp.example.com');
define('SMTP_PORT',   587);
define('SMTP_USER',   '[email protected]');
define('SMTP_PASS',   'super-secret-password');
define('SMTP_SECURE', 'tls'); // 'ssl' | 'tls' | ''
define('SMTP_AUTH',   true);
define('SMTP_FROM',   '[email protected]');
define('SMTP_NAME',   'Example Site');

wp-content/mu-plugins/smtp.php

<?php
/*
Plugin Name: Site SMTP (No Plugins Needed)
Description: Forces all wp_mail() to use provider SMTP.
*/

add_action('phpmailer_init', function ($phpmailer) {
    $phpmailer->isSMTP();
    $phpmailer->Host       = SMTP_HOST;
    $phpmailer->Port       = (int)SMTP_PORT;
    $phpmailer->SMTPAuth   = (bool)SMTP_AUTH;
    $phpmailer->Username   = SMTP_USER;
    $phpmailer->Password   = SMTP_PASS;
    $phpmailer->SMTPSecure = SMTP_SECURE;
    if (empty($phpmailer->SMTPSecure)) {
        $phpmailer->SMTPAutoTLS = false;
    }
    $phpmailer->setFrom(SMTP_FROM, SMTP_NAME, false);
});

add_filter('wp_mail_from',      fn($email) => SMTP_FROM);
add_filter('wp_mail_from_name', fn($name)  => SMTP_NAME);

FAQ

Does this survive theme changes?
Yes – if you place it in mu-plugins. If you put the hook in a theme’s functions.php, it depends on that theme.

Will core updates overwrite this?
No, your wp-config.php and mu-plugins/ are untouched by core updates.

Can I send different “From” per site on multisite?
Yes – set per-site constants (domain-specific wp-config.php).

If you’d like us to wire this up across environments (dev/stage/prod), integrate with your provider, and add basic delivery checks, we can help. We build scalable, reliable WordPress and Laravel systems with lean ops.

Worth passing on?Share this article.
Link copied

Discussion

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *

Continue reading

Related articles.

View all articles

Have a development problem?

Let’s turn it into working software.

Free intro call Choose a time that works.

Please book thoughtfully. Choose a time only if you have a real project or technical problem to discuss, or we are already in contact. For general questions, please use the contact form.