Assume we have blank WP site and we want to setup SMTP settings programmatically in our plugin or theme. What's the easiest way to do it without changing core files?
3 Answers
First of all, if we take a look at implementation of wp_mail
function, we will see that this function uses PHPMailer
class to send emails. Also we could notice that there is hard coded function call $phpmailer->IsMail();
, which sets to use PHP's mail()
function. It means that we can't use SMTP settings with it. We need to call isSMTP
function of PHPMailer
class. And also we need to set our SMTP settings as well.
To achieve it we need to get access to $phpmailer
variable. And here we come to phpmailer_init
action which is called before sending an email. So we can do what we need by writing our action handler:
add_action( 'phpmailer_init', 'wpse8170_phpmailer_init' );
function wpse8170_phpmailer_init( PHPMailer $phpmailer ) {
$phpmailer->Host = 'your.smtp.server.here';
$phpmailer->Port = 25; // could be different
$phpmailer->Username = '[email protected]'; // if required
$phpmailer->Password = 'yourpassword'; // if required
$phpmailer->SMTPAuth = true; // if required
// $phpmailer->SMTPSecure = 'ssl'; // enable if required, 'tls' is another possible value
$phpmailer->IsSMTP();
}
And that's all.
-
Nice stuff, Eugene, thx! I guess this 10 lines of code can substitute an entire SMTP plugin...(?) Commented Dec 13, 2012 at 11:59
-
@brasofilo thx! I think it can't substitute a SMTP plugin, because the plugin allows you to configure settings at admin panel. This snippet is just best practice about "how to change email settings programmatically" without breaking core files or without rewriting
wp_mail
function. Commented Dec 13, 2012 at 12:40 -
2Where should this code be placed? I want to make all my themes use the same SMTP servers.– AnjanCommented Jan 10, 2014 at 14:43
-
2Very strange WP does not make this easier as you would think it would be a common to modify this. Commented Apr 30, 2015 at 13:14
-
1it works for me, @JackNicholson you should check it on your end too. Commented Nov 9, 2015 at 14:41
Addition to @EugeneManuilov answer.
SMTP settings
By default those can only get - as @EugeneManuilov already answered - be set by during a callback attached to an do_action_ref_array()
. Source/core.
<?php
defined( 'ABSPATH' ) OR exit;
/**
* Plugin Name: (WCM) PHPMailer SMTP Settings
* Description: Enables SMTP servers, SSL/TSL authentication and SMTP settings.
*/
add_action( 'phpmailer_init', 'phpmailerSMTP' );
function phpmailerSMTP( $phpmailer )
{
# $phpmailer->IsSMTP();
# $phpmailer->SMTPAuth = true; // Authentication
# $phpmailer->Host = '';
# $phpmailer->Username = '';
# $phpmailer->Password = '';
# $phpmailer->SMTPSecure = 'ssl'; // Enable if required - 'tls' is another possible value
# $phpmailer->Port = 26; // SMTP Port - 26 is for GMail
}
SMTP Exceptions
Per default WordPress doesn't give you any debug output. Instead it just returns FALSE
if an error occurred. Here's small plugin to fix this:
<?php
defined( 'ABSPATH' ) OR exit;
/**
* Plugin Name: (WCM) PHPMailer Exceptions & SMTP
* Description: WordPress by default returns <code>FALSE</code> instead of an <code>Exception</code>. This plugin fixes that.
*/
add_action( 'phpmailer_init', 'WCMphpmailerException' );
function WCMphpmailerException( $phpmailer )
{
if ( ! defined( 'WP_DEBUG' ) OR ! WP_DEBUG )
{
$phpmailer->SMTPDebug = 0;
$phpmailer->debug = 0;
return;
}
if ( ! current_user_can( 'manage_options' ) )
return;
// Enable SMTP
# $phpmailer->IsSMTP();
$phpmailer->SMTPDebug = 2;
$phpmailer->debug = 1;
// Use `var_dump( $data )` to inspect stuff at the latest point and see
// if something got changed in core. You should consider dumping it during the
// `wp_mail` filter as well, so you get the original state for comparison.
$data = apply_filters(
'wp_mail',
compact( 'to', 'subject', 'message', 'headers', 'attachments' )
);
current_user_can( 'manage_options' )
AND print htmlspecialchars( var_export( $phpmailer, true ) );
$error = null;
try
{
$sent = $phpmailer->Send();
! $sent AND $error = new WP_Error( 'phpmailerError', $sent->ErrorInfo );
}
catch ( phpmailerException $e )
{
$error = new WP_Error( 'phpmailerException', $e->errorMessage() );
}
catch ( Exception $e )
{
$error = new WP_Error( 'defaultException', $e->getMessage() );
}
if ( is_wp_error( $error ) )
return printf(
"%s: %s",
$error->get_error_code(),
$error->get_error_message()
);
}
Repository
The plugins are both available in this Gist on GitHub, so consider checking those plugins out from there to grab any updates.
The other answers to this post, while providing a working solution, don't address the security issue of storing your SMTP credentials in a plugin file or functions.php. In some cases that may be OK, but best practices would dictate storing this information in a more secure fashion. There's really not a good reason to not follow best practices when it comes to protecting your credentials.
Some would suggest saving it to the DB as an option, but also provides the same security issues depending on the number of administrative users your site has and whether those users should be able to see these login credentials. This is also the same reason to not use a plugin for this.
The best way to do this is to define constants for the phpmailer info in your wp-config.php file. This actually has been discussed as a feature in the Mail Component, but hasn't been accepted as an actual enhancement at this time. But you can do it yourself by adding the following to wp-config.php:
/**
* Set the following constants in wp-config.php
* These should be added somewhere BEFORE the
* constant ABSPATH is defined.
*/
define( 'SMTP_USER', '[email protected]' ); // 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', '[email protected]' ); // 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
Once these are defined in wp-config.php, they can be used anywhere by using the defined constant. So you could use those in a plugin file or in your functions.php. (Specific to the OP, use a plugin file.)
/**
* This function will connect wp_mail to your authenticated
* SMTP server. Values are constants set in wp-config.php
*/
add_action( 'phpmailer_init', 'send_smtp_email' );
function send_smtp_email( $phpmailer ) {
$phpmailer->isSMTP();
$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;
}
There is a little more detail on this in this post and a gist on github here.
-
-
3Small addition: Needless to say, don't store credentials in version control. Use gitignored
.env
file instead. But nobody who puts anything sensitive intowp-config.php
is using version control, anyway…– jsphplCommented Aug 29, 2018 at 15:32