-
-
Save butlerblog/c5c5eae5ace5bdaefb5d to your computer and use it in GitHub Desktop.
<?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', '[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 |
/** | |
* 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; | |
} |
@mikeritter: that seams logical!
could i just add this snippet to my wpconfig.php file?!
in the theme functions.php it has nothing to do - because i think it has nothing to do with a theme!
and adding a 'about empty' plugin for this is also over complex i think. --> but if i have to do it this way can you link to some documentation how to use the wpconfig.php for the configuration parameters and receive theme in the plugins funciton.php?
(i know there are ready build plugins out there - but hey i want to learn this stuff :-) )
@mikeritter - the security difference between putting credentials in functions.php vs wp-config.php is negligible. In most cases, if your functions.php file is compromised, so is your wp-config.php (which in many cases means your database is also compromised). The ideal situation is to store them as a db entry, and use a configuration that restricts db access by IP (or similar security) so that the db credentials in wp-config.php do not necessarily allow access to the database. But that is outside the scope of this snippet.
@butlerblog, that's not necessarily true. People who have admin access to your WP installation would be able to see functions.php, but you may not want them to have the ability to change or see the credentials. wp-config.php keeps it away from users, if that's your goal.
@mikeritter, can I use this to send mail for SENDGRID?
If yes, that means I will have to copy the contents of the first file and paste in my wp_config.php, where do I necessarily need to put these files?
If anyone has had issues using this gist, the $phpmailer->isSMTP();
line may be throwing an error.
Change $phpmailer->isSMTP();
to $phpmailer->Mailer = 'smtp';
and pass $phpmailer
as the function's arg. It also wouldn't hurt to ensure $phpmailer
is, in fact, an object in the event some other code has turned it into an array.
In full, the function should be:
add_action( 'phpmailer_init', function( $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;
});
Is it possible to do without auth credentials (like in Nodemailer)?
I'll reiterate that this functionality does NOT belong in a theme's functions.php file. This is site functionality which should never be put in a theme. Themes should only be for site styling and UX.
Hi all.
I would also add the following filters
add_filter('wp_mail_from', 'set_wp_mail_from');
function set_wp_mail_from($current_from) {
if (SMTP_FROM) {
return SMTP_FROM;
}
if ($current_from) {
return $current_from;
}
return get_bloginfo('admin_email');
}
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;
}
if ($current_from_name) {
return $current_from_name;
}
return get_bloginfo('name');
}
The reason for this is that, the phpmailer_init
hook won't even be fired if FROM
isn't set before, because the WordPress code will throw an error before even reaching do_action
saying that from_email is invalid, unless somehow it is valid.
@progress44 - In a standard install of WP, that would be unnecessary. From
and FromName
are always set with defaults (with a caveat noted below*).
If these two values are not set in the headers, wp_mail()
defines defaults for $from_mail
and $from_name
. As you've noted, it then hits the wp_mail_from
and wp_mail_from_name
filter hooks respectively, but those hooks are filtering the already generated default values.
If they are not filtered, the defaults are "[email protected]" and "WordPress", which will be set in as $phpMailer->From
and $phpMailer->FromName
when $phpmailer->setFrom()
is run immediately following the filter hooks. Those values will be changed when the phpmailer_init
hook is fired and the send_smtp_email()
function in this gist is run.
*There is a caveat to this (which could be the case which prompted your comment): wp_mail()
IS a pluggable function. As such, it can be entirely replaced by a plugin (or other customization), in which case there is no guarantee that the email and name were given a default value. But neglecting a default value in a plugged (customized) wp_mail()
function would be bad form on the part of that developer, IMO. If you're running into a situation that requires this, I would recommend reviewing what plugins are active and if any of them may possibly redefine the wp_mail()
function (then determine if that plugin is actually necessary).
Thanks for sharing. I tried the code, but the emails are still sent via phpmailer. Using the very same credentials in a plugin like "WP Mail SMTP" everything works just fine. I would really avoid a plugin for such a simple task, but have not idea what's going wrong. Anybody any ideas?
Wondering if this git is still up-to-date, regarding the PHP Mailer update in WordPress 5.5.
Please advise.
As far as I know, it's working fine with WP 5.5. There weren't any changes to PHP Mailer that I'm aware of that would render it invalid.
I'm having trouble making this work I've been trying to do so for days now.
I used a plugin that does that and it worked correctly, but I want to do it this way.
Does anyone have an idea on how to debug this wp-mail function?
@butlerblog Stopped working for me as well, 5.5 did introduce new phpmailer changes.. maybe the class isn't being imported? i enabled debug logging but don't get any errors in it. still not email though..
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.
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';
And further to my previous question, are the following snippets required following the recent Wordpress update to 5.5 - https://stackoverflow.com/a/64736911
@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.)
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?)
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
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...');
}
I'd recomment against hard coding the credentials into this file and for adding them to
wpconfig.php
You do not want these credentials in your
functions.php
file or (as arguably, this shoud be a plugin) in a plugin file.