Skip to content

Instantly share code, notes, and snippets.

@butlerblog
Last active February 1, 2024 09:00
Show Gist options
  • Save butlerblog/c5c5eae5ace5bdaefb5d to your computer and use it in GitHub Desktop.
Save butlerblog/c5c5eae5ace5bdaefb5d to your computer and use it in GitHub Desktop.
Configure WordPress #wp_mail function to send through #SMTP server https://b.utler.co/Y3
<?php
/*
* Set the following constants in wp-config.php.
* These should be added somewhere BEFORE the constant ABSPATH is defined.
*
* Author: Chad Butler
* Author URI: https://butlerblog.com
*
* For more information and instructions, see: https://b.utler.co/Y3
*/
define( 'SMTP_USER', 'user@example.com' ); // Username to use for SMTP authentication
define( 'SMTP_PASS', 'smtp password' ); // Password to use for SMTP authentication
define( 'SMTP_HOST', 'smtp.example.com' ); // The hostname of the mail server
define( 'SMTP_FROM', 'website@example.com' ); // SMTP From email address
define( 'SMTP_NAME', 'e.g Website Name' ); // SMTP From name
define( 'SMTP_PORT', '25' ); // SMTP port number - likely to be 25, 465 or 587
define( 'SMTP_SECURE', 'tls' ); // Encryption system to use - ssl or tls
define( 'SMTP_AUTH', true ); // Use SMTP authentication (true|false)
define( 'SMTP_DEBUG', 0 ); // for debugging purposes only set to 1 or 2
/**
* This function will connect wp_mail to your authenticated
* SMTP server. This improves reliability of wp_mail, and
* avoids many potential problems.
*
* Values are constants set in wp-config.php. Be sure to
* define the using the wp_config.php example in this gist.
*
* Author: Chad Butler
* Author URI: https://butlerblog.com
*
* For more information and instructions, see: https://b.utler.co/Y3
*/
add_action( 'phpmailer_init', 'send_smtp_email' );
function send_smtp_email( $phpmailer ) {
if ( ! is_object( $phpmailer ) ) {
$phpmailer = (object) $phpmailer;
}
$phpmailer->Mailer = 'smtp';
$phpmailer->Host = SMTP_HOST;
$phpmailer->SMTPAuth = SMTP_AUTH;
$phpmailer->Port = SMTP_PORT;
$phpmailer->Username = SMTP_USER;
$phpmailer->Password = SMTP_PASS;
$phpmailer->SMTPSecure = SMTP_SECURE;
$phpmailer->From = SMTP_FROM;
$phpmailer->FromName = SMTP_NAME;
}
@butlerblog
Copy link
Author

The WordPress 5.5 changes to phpMailer have no effect on this. I use this exact method on my production sites, and as a component maintainer for the WordPress Mail component, I keep up-to-date on the changes. That's not to say things don't get missed, but more often than not, the issue is on the other end.

Confirm that no changes were made by your email host. This includes ports and authentication schemes, as well as making sure they're not blocking your remote connection. Make sure that if you change your password, you reflect that change.

@adeyjones
Copy link

Hi, just found this function and it looks exactly what I need, but I have around 160 sites which are all clones of each other and would like to introduce this to all. I can update my theme centrally so would rather have it all in functions.php as I can do this remotely rather than manually having to edit the wp-config.php for each site, but nobody else has admin access to any of the sites and I will set up a dedicated account on the server for this. Question is how do I adapt the function to accommodate the details, is it as simple as
$phpmailer->Host = 'mail.example.com';

@adeyjones
Copy link

And further to my previous question, are the following snippets required following the recent Wordpress update to 5.5 - https://stackoverflow.com/a/64736911

@butlerblog
Copy link
Author

@adeyjones - Yes, you could do it as you described, but I wouldn't go on record as saying that's in any way safe. Ease of implementation should not override security in making decisions. Why not define the settings in a single include file outside the web root. Then every one of your sites could include the same settings when invoking the object.

As far as changes to PHPMailer in WP, the question you need to ask is "Did PHPMailer change the variable names in the object?" The answer to that is "no." This snippet is setting the connection values when the WP action "phpmailer_init" is fired. That of course assumes PHPMailer is already loaded and is being initialized. Whether you need to include the PHPMailer object to begin with depends entirely on the use case in which you are implementing this and is outside the scope of this discussion. (In plain terms, the question has nothing to do with whether this works or not. Don't overthink it.)

@adeyjones
Copy link

Thanks for the reply, glad I don't need to worry about anything other than setting what is needed here.

So when you said include a file outside the web root, did you mean perhaps including the settings in a PHP file in the hosting account for my main website perhaps (example.com/file.php) and then include that in my 160+ sites (I assume including an external file in functions.php is allowed?)

@butlerblog
Copy link
Author

If you save it in another site, that's still the web root for that site. I'm talking about keeping it outside your web root. BTW, you can do that for the entire wp config as well. See: https://wordpress.stackexchange.com/questions/58391/is-moving-wp-config-outside-the-web-root-really-beneficial

@jmarshall9120
Copy link

This doesn't work for me. I've implemented exactly as shown, but I get this:

`[0] => Invalid address:  (From): wordpress@localhost`

I was forced to implement these hooks as well:

add_filter('wp_mail_from', 'set_wp_mail_from');
function set_wp_mail_from($current_from) {
	if (SMTP_FROM) { 
		return SMTP_FROM;
	}
	throw new Exception('SMTP_FROM not detected...');
}

add_filter('wp_mail_from_name', 'set_wp_mail_from');
function set_wp_mail_from_name($current_from_name) {
	if (SMTP_NAME) {
		return SMTP_NAME;	
	}
	throw new Exception('SMTP_NAME not detected...');
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment