I add the following code to the functions.php
file.
add_action( 'phpmailer_init', 'my_phpmailer_example' );
function my_phpmailer_example( $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;
}
and wp-config.php
// SMTP email settings
define( 'SMTP_USER', '{email}' );
define( 'SMTP_PASS', '{password}' );
define( 'SMTP_HOST', '{server}' );
define( 'SMTP_FROM', '{from}' );
define( 'SMTP_NAME', '{name}' );
define( 'SMTP_PORT', '465' );
define( 'SMTP_SECURE', 'ssl' );
define( 'SMTP_AUTH', true );
“wp-login.php?action=lostpassword
” when I go here, I enter my e-mail address and click the send button,
“Failed to send e-mail. Your site may not be properly configured to send e-mail.” I am getting this error.
But when I paste the same code into another WordPress with WooCommerce plugin installed,
I forgot my WooCommerce password. Mail can be successfully sent from the front-end design.
Where is the problem? Am I doing something wrong?
3rd step
add_action( 'wp_mail_failed', function ( $error ) {
error_log( $error->get_error_message() );
} );
Not working (IDK). But I searched and found the code below,
add_action('wp_mail_failed', 'log_mailer_errors', 10, 1);
function log_mailer_errors( $wp_error ){
$fn = ABSPATH . '/mail.log'; // say you've got a mail.log file in your server root
$fp = fopen($fn, 'a');
fputs($fp, "Mailer Error: " . $wp_error->get_error_message() ."\n");
fclose($fp);
}
This gave me the following error
Mailer Error: Invalid address: (From): wordpress@localhost
I found the relevant location from pluggable.php
.
Since I was working on localhost, it was emitting an invalid e-mail address because it did not create a valid TLD.
if ( ! isset( $from_email ) ) {
// Get the site domain and get rid of www.
$sitename = wp_parse_url( network_home_url(), PHP_URL_HOST );
if ( 'www.' === substr( $sitename, 0, 4 ) ) {
$sitename = substr( $sitename, 4 );
}
$from_email="wordpress@" . $sitename;
}
This means, “$phpmailer->From = SMTP_FROM;
” instead of “add_filter ('wp_mail_from', 'set_from');
” should use.
function set_from()
{
return 'name@domain.tld';
}
add_filter('wp_mail_from', 'set_from');
Works now.
I don’t understand why
phpmailer_init
doesn’t overwrite from information.
By the way, the sender still appears to be what I defined in ($phpmailer-> From
).
I guess this is some kind of bug and should be reported to WordPress?
1
Where is the problem? Am I doing something wrong?
Your code seems fine to me, so despite I can’t give you a definitive answer on what/where exactly is the problem, I thought these might help you troubleshoot the issue:
-
First and foremost, check your configuration — e.g. did you use the correct (SMTP) username/email, password, host?
And make sure the
SMTP_FROM
value is a valid email addresss — e.g.user@example.com
and notuser@example
orUser <user@example.com>
; otherwise, the email will not be sent. -
If you’re sure the configuration is good, then because you’re using SMTP, try enabling debugging like so — add this to your
my_phpmailer_example()
function:// Note: I assumed you're using at least WordPress version 5.5.0 $phpmailer->SMTPDebug = PHPMailer\PHPMailer\SMTP::DEBUG_SERVER;
Then visit the WordPress’s password reset page and try to reset your password, and on the next page, if PHPMailer was unable to send the email, then you’d see the error message displayed at the top of the page.
-
If you can’t do the SMTP debugging above (which is just a quick troubleshooting, actually), then enable debugging in WordPress and use the
wp_mail_failed
hook to try to catch any errors in sending the email — add this to the functions file:add_action( 'wp_mail_failed', function ( $error ) { error_log( $error->get_error_message() ); } );
Then check the
wp-content/debug.log
file and see if there’s any relevant errors/information.
Update
(sorry, I couldn’t resist from saying this) I liked this question and I’m glad that you managed to fix the issue. 🙂
I guess this is some kind of bug and should be reported to WordPress?
Maybe, but it’s definitely a good thing if they could do something to avoid the issue from happening, particularly because there are many folks who develop on localhost
.
But just in case you’re not aware of it, you could actually use virtual hosts like localhost.dev
and that way, the issue could be avoided.
Since I was working on localhost, it was emitting an invalid e-mail
address because it did not create a valid TLD.
Yes, and I guessed you’ve already seen this note in the wp_mail()
code (in pluggable.php
):
/*
* If we don't have an email from the input headers, default to wordpress@$sitename
* Some hosts will block outgoing mail from this address if it doesn't exist,
* but there's no easy alternative. Defaulting to admin_email might appear to be
* another option, but some hosts may refuse to relay mail from an unknown domain.
* See https://core.trac.wordpress.org/ticket/5007.
*/
So yes, either use the wp_mail_from
hook or as I said above, use a virtual host.
I don’t understand why
phpmailer_init
doesn’t overwrite from
information.
Because WordPress/wp_mail()
calls $phpmailer->setFrom()
to set the From
property and if PHPMailer throws an exception/error (e.g. due to invalid email address), then wp_mail()
returns false
and never fires the phpmailer_init
hook.
But the wp_mail_failed
hook does get fired, therefore it’s a very good way to catch any errors which may occur when sending an email using wp_mail()
. ( and sorry, I didn’t mention it earlier because I thought the SMTP debugging would work for you as well 🙂 )
By the way, the sender still appears to be what I defined in (
$phpmailer->From
).
Yes, that’s normal, because the setFrom()
is called before the phpmailer_init
hook is fired.
And actually, when I said “enable debugging in WordPress”, I meant set both the WP_DEBUG
and WP_DEBUG_LOG
constants to true
; and if error_log()
doesn’t write to wp-content/debug.log
(or the file defined via the WP_DEBUG_LOG
constant), then you could use the 2nd and 3rd parameters for error_log()
like so:
add_action( 'wp_mail_failed', function ( $error ) {
// the "3" means write the message to the file as defined in the third parameter
error_log( $error->get_error_message(), 3, WP_CONTENT_DIR . '/debug.log' );
} );
But anyway, I hope this answer/update and the question also help someone else. =) Happy coding!