WordPress.org

Make WordPress Core

Opened 9 years ago

Closed 20 months ago

Last modified 8 months ago

#21095 closed defect (bug) (fixed)

Reset password link is in < RESET_URL > - Gmail does not show it.

Reported by: tommix Owned by: SergeyBiryukov
Milestone: 5.4 Priority: normal
Severity: normal Version: 3.4
Component: Mail Keywords: has-patch needs-testing dev-feedback
Focuses: Cc:

Description

This is not WP bug, but WP sends password in "<" and ">" and google looks like filtering it and in mail there is no link. If i remove those simbols from wp-login.php
$message .= '<' . network_site_url("wp-login.php?action=rp&key=$key&login=" . rawurlencode($user_login), 'login') . ">\r\n";

Then link is in email. SO we have to change < > to let's say ( ).

Attachments (2)

pass.png (28.8 KB) - added by tommix 9 years ago.
First mail - withouth changing wp-login.php, second -after changes.
21095.patch (941 bytes) - added by sebastian.pisula 2 years ago.
Patch

Download all attachments as: .zip

Change History (37)

#1 @evansolomon
9 years ago

I just tested this and it works fine for me, the link is there and clickable.

I do think the less than/greater than signs look a little weird -- the email would be better, in my opinion, if they were removed entirely -- but they don't seem to actually break anything.

Last edited 9 years ago by evansolomon (previous) (diff)

#2 @dd32
9 years ago

They actually serve a purpose, They define the start and endings of links in Plain Text emails, many (at least older) email clients that only use Plain Text required <..> around url's to define the boundaries, It's more of a problem when the link is long and wraps onto a second line.

It's part of the Plain Text email RFC from memory, and is also recommended for other addressing methods in plain text.

The "proper" thing here IMO, isn't to change the Plain text emails to be "prettier" but instead, to implement proper HTML emails so that we can style things properly: #18493

#3 @dd32
9 years ago

That being said, I find it hard to believe Gmail is including the brackets in the link, as I use plain text emails in Gmail every day which use that syntax.. I'd expect it to be caused by a browser addon myself.

#4 @tommix
9 years ago

I'm using HTML mails, i did it in functions.php file, and you all maybe using Plain text.
Hard to believe or no - it DOESN't show reset url. not for me only, my friend first told me about this, i was thinking maybe plugin causes this, but no, after i changed wp-login.php file to remove < > -it worked.

Last edited 9 years ago by tommix (previous) (diff)

@tommix
9 years ago

First mail - withouth changing wp-login.php, second -after changes.

#5 @tommix
9 years ago

  • Summary changed from Reset password link is in < URL > - Gmail does not show it. to Reset password link is in < RESET_URL > - Gmail does not show it.

#6 follow-up: @dd32
9 years ago

  • Keywords close added; needs-patch removed

I'm using HTML mails, i did it in functions.php file, and you all maybe using Plain text.

Then the Plain text -> HTML markup processing is faulty in your modifications/plugin/theme, It's probably just using content passed verbatim instead of escaping the content for display in HTML emails, that's not a core problem.

#7 in reply to: ↑ 6 @tommix
9 years ago

Replying to dd32:

I'm using HTML mails, i did it in functions.php file, and you all maybe using Plain text.

Then the Plain text -> HTML markup processing is faulty in your modifications/plugin/theme, It's probably just using content passed verbatim instead of escaping the content for display in HTML emails, that's not a core problem.

WORDPRESS sends reset emails, not themes. So this is core problem. I do not process any mails.
People please if you comment - enable HTML mails in WP, use reset password function with GMail and them write your opinions. This is the basic WP function, nobody changes it, why theme have to change something? I'm sending many URLs and all is working exept this one.

#8 follow-up: @dd32
9 years ago

enable HTML mails in WP

WordPress does not send HTML emails at present. How are you enabling HTML emails in the first place?

#9 in reply to: ↑ 8 @tommix
9 years ago

Replying to dd32:

enable HTML mails in WP

WordPress does not send HTML emails at present. How are you enabling HTML emails in the first place?

WP doesnt send html, it sends text but mail type (header) is changed to HTML.

function html_laiskai(){
    return "text/html";
}
add_filter( 'wp_mail_content_type','html_laiskai' );
Last edited 8 years ago by SergeyBiryukov (previous) (diff)

#10 follow-up: @dd32
9 years ago

  • Component changed from Users to Mail

WP doesnt send html, it sends text but mail type (header) is changed to HTML.

By changing the mime type, you're forcing the WordPress plain text emails content to be parsed as HTML, Since html uses < and > for tags, it's causing the content to break. Since you're not doing any further processing to the emails, it sounds like setting the content type for all emails isn't what you should be doing, it won't suddenly make emails better.

So, Either stop doing that, or also apply esc_html to the mail body, and it'll work as you expect.

You'd need to do something like this: (untested)

add_filter( 'wp_mail', 'html_email_encode_body' );
function html_email_encode_body( $mail ) {
  $mail['message'] = esc_html( $mail['message'] );
  return $mail;
}

#11 in reply to: ↑ 10 @tommix
9 years ago

Replying to dd32:

WP doesnt send html, it sends text but mail type (header) is changed to HTML.

By changing the mime type, you're forcing the WordPress plain text emails content to be parsed as HTML, Since html uses < and > for tags, it's causing the content to break. Since you're not doing any further processing to the emails, it sounds like setting the content type for all emails isn't what you should be doing, it won't suddenly make emails better.

So, Either stop doing that, or also apply esc_html to the mail body, and it'll work as you expect.

You'd need to do something like this: (untested)

add_filter( 'wp_mail', 'html_email_encode_body' );
function html_email_encode_body( $mail ) {
  $mail['message'] = esc_html( $mail['message'] );
  return $mail;
}

Well this helped for reset email but messed up my real HTML mails, now it just plaint html source.

Last edited 9 years ago by tommix (previous) (diff)

#12 @dd32
9 years ago

  • Milestone Awaiting Review deleted
  • Resolution set to invalid
  • Status changed from new to closed

Well this helped for reset email but messed up my real HTML mails, now it just plaint html source.

In that case, You'll need to only change the mimetype for the emails you're sending, not the core ones, You can do that by something similar to the following - which is how this filter was seemingly intended on being used, on a per-email basis by adding and removing the filter.

....
add_filter( 'wp_mail_content_type','html_laiskai' );
wp_mail( my html messages );
remove_filter( 'wp_mail_content_type','html_laiskai' );

Closing as invalid since WordPress was doing exactly as you were asking (Note, you can still reply without re-opening the ticket if need be)

#13 follow-up: @tommix
9 years ago

Well i wouldn't say that this ticket is invalid, it is valid, and this is some kind of bug. All mails should by default be HTML type. We what living in 90's? It's stupid to everytime you want to send mail to apply filters, send mail and then undo filters. I'd better change core file and that's it. No need to put urls in < >

#14 in reply to: ↑ 13 ; follow-up: @SergeyBiryukov
9 years ago

Replying to tommix:

All mails should by default be HTML type.

And we already have a ticket for that: #18493.

No need to put urls in < >

Per #14140, there's a reason for them to be there.

#15 in reply to: ↑ 14 @tommix
9 years ago

Replying to SergeyBiryukov:

No need to put urls in < >

Per #14140, there's a reason for them to be there.

So his problem is important and mine no? I don't see reason why broken links is worse than no links at all in mail.

#16 @SergeyBiryukov
9 years ago

In your case, the links are only missing when the message is incompletely converted to HTML, not by default.

Implementing HTML emails in a consistent manner makes more sense to me than reverting a valid fix in order to support an incomplete workaround.

#17 @vscotth
8 years ago

  • Resolution invalid deleted
  • Status changed from closed to reopened

So I'm having the same problem... the link is in the email source, but not displayed because of the brackets. After reading this thread, I'm not clear what the solution is. Should I modify the functions.php file, or create a functions.php file in a child theme? I'd really like the reset password functionality to work.

#18 follow-up: @SergeyBiryukov
8 years ago

  • Resolution set to invalid
  • Status changed from reopened to closed

If your theme uses wp_mail_content_type filter to change the MIME type to text/html for all outgoing emails, the solution is to stop doing that and only enable that filter where you need it (see comment:10 and comment:12).

Please try the support forums if you need theme-specific instructions: http://wordpress.org/support/.

#19 @SergeyBiryukov
7 years ago

#30263 was marked as a duplicate.

#20 follow-up: @sablednah
7 years ago

I found this bug too. Turns out it was the Mandril plugin.

It seems to malform the link removing "<html:/" in plain text and retain the <URLHERE> format in html - which is an invalid html tag and therefore not visible.

Just leaving this here incase google leads others here...

#21 in reply to: ↑ 20 @austinpray
7 years ago

Replying to sablednah:

I found this bug too. Turns out it was the Mandril plugin.

It seems to malform the link removing "<html:/" in plain text and retain the <URLHERE> format in html - which is an invalid html tag and therefore not visible.

Just leaving this here incase google leads others here...

What ended up being the solution?

#22 in reply to: ↑ 18 ; follow-up: @julian.kimmig
6 years ago

Replying to SergeyBiryukov:

If your theme uses wp_mail_content_type filter to change the MIME type to text/html for all outgoing emails, the solution is to stop doing that and only enable that filter where you need it (see comment:10 and comment:12).

Please try the support forums if you need theme-specific instructions: http://wordpress.org/support/.

If someone doesn't want to do that is it possible to fix this by removing the < & > when in your custom filter:

add_filter( 'wp_mail', 'dirty_wp_mail_filter' );
function dirty_wp_mail_filter( $args ) {

	// you can include your custom html mail template here
	// just use file_get_contents() functions to get template file and any php replace function like
	// str_ireplace or preg_replace to replace your given placeholder in template by the content which is sent by wp

	$stripped_mail_content = preg_replace("/<http(.*)>/m", "http$1", $args['message']);
	add_filter( 'wp_mail_content_type', 'dirty_notification_content_type' );
	$dirty_wp_mail = array(
		'to'          => $args['to'],
		'subject'     => $args['subject'],
		'message'     => $stripped_mail_content,
		'headers'     => $args['headers'],
		'attachments' => $args['attachments']
	);
	return $dirty_wp_mail;
}

function dirty_notification_content_type() {
	return 'text/html';
}

some kind of dirty for some of u.. but i hope this helps, too. :)

#23 in reply to: ↑ 22 @Rahe
6 years ago

Replying to julian.kimmig:

Replying to SergeyBiryukov:

If your theme uses wp_mail_content_type filter to change the MIME type to text/html for all outgoing emails, the solution is to stop doing that and only enable that filter where you need it (see comment:10 and comment:12).

Please try the support forums if you need theme-specific instructions: http://wordpress.org/support/.

If someone doesn't want to do that is it possible to fix this by removing the < & > when in your custom filter:

add_filter( 'wp_mail', 'dirty_wp_mail_filter' );
function dirty_wp_mail_filter( $args ) {

	// you can include your custom html mail template here
	// just use file_get_contents() functions to get template file and any php replace function like
	// str_ireplace or preg_replace to replace your given placeholder in template by the content which is sent by wp

	$stripped_mail_content = preg_replace("/<http(.*)>/m", "http$1", $args['message']);
	add_filter( 'wp_mail_content_type', 'dirty_notification_content_type' );
	$dirty_wp_mail = array(
		'to'          => $args['to'],
		'subject'     => $args['subject'],
		'message'     => $stripped_mail_content,
		'headers'     => $args['headers'],
		'attachments' => $args['attachments']
	);
	return $dirty_wp_mail;
}

function dirty_notification_content_type() {
	return 'text/html';
}

some kind of dirty for some of u.. but i hope this helps, too. :)

Thank you for the temporary patch, I have improved it because of possible https sites and maybe the 'message' index does not exists :

function dirty_wp_mail_filter( $args ) {

	/**
	 * Get HTML or message
	 */
	$index = isset( $args['html'] ) ? 'html' : 'message';

	// you can include your custom html mail template here
	// just use file_get_contents() functions to get template file and any php replace function like
	// str_ireplace or preg_replace to replace your given placeholder in template by the content which is sent by wp
	// Fix content taking into account the http/https
	$args[$index] = preg_replace("/\<((https|http)(.*))\>/", "$2$3", $args[$index] );

	add_filter( 'wp_mail_content_type', 'dirty_notification_content_type' );

	return $args;
}

Mayeb this can help somebody too :)

#24 follow-up: @clayisland
5 years ago

Hi,
I was having the problem of the reset link being hidden in my emails (and visible in the source). I was using a smtp plugin and the end of my email source looked like this:

Someone has requested a password reset for the following account:

http://mydomain.com/

Username: [email protected]

If this was a mistake, just ignore this email and nothing will happen.

To reset your password, visit the following address:

<http://mydomain.com/wp-login.php?action=rp&key=hereisthekey&login=myemail%40gmail.com>

So what ended up working for me is deactivating the plugin I was using and installing and activating the plugin: Postman SMTP.
https://wordpress.org/plugins/postman-smtp/

Now my the password reset link is visible in emails and the end my email source looks like this:

Someone requested that the password be reset for the following account:=
=0D=0A=0D=0Ahttp://mydomain.com/=0D=0A=0D=0AUsername: myemail@=
gmail.com=0D=0A=0D=0AIf this was a mistake, just ignore this email and n=
othing will happen.=0D=0A=0D=0ATo reset your password, visit the followi=
ng address:=0D=0A=0D=0A<http://mydomain.com/resetpass/?key=hereisthekey&login=3Dmyemail%40gmail.com>=0D=0A

I hope this helps!
I searched for a solution and ended up being more confused by the various suggestions as to the what the culprit was and how to go about fixing it. So hopefully this is a wise solution and I will have no more issues. If someone knows a problem with this fix and a better way please enlighten me.

Thanks!

#25 in reply to: ↑ 24 @arenddeboer
4 years ago

Bummer, this unfortunately didn't work for me.
What did work was installing TML (theme my login) and enble custom emails, and write your own email template.

Replying to clayisland:

Hi,
I was having the problem of the reset link being hidden in my emails (and visible in the source). I was using a smtp plugin and the end of my email source looked like this:

Someone has requested a password reset for the following account:

http://mydomain.com/

Username: [email protected]

If this was a mistake, just ignore this email and nothing will happen.

To reset your password, visit the following address:

<http://mydomain.com/wp-login.php?action=rp&key=hereisthekey&login=myemail%40gmail.com>

So what ended up working for me is deactivating the plugin I was using and installing and activating the plugin: Postman SMTP.
https://wordpress.org/plugins/postman-smtp/

Now my the password reset link is visible in emails and the end my email source looks like this:

Someone requested that the password be reset for the following account:=
=0D=0A=0D=0Ahttp://mydomain.com/=0D=0A=0D=0AUsername: myemail@=
gmail.com=0D=0A=0D=0AIf this was a mistake, just ignore this email and n=
othing will happen.=0D=0A=0D=0ATo reset your password, visit the followi=
ng address:=0D=0A=0D=0A<http://mydomain.com/resetpass/?key=hereisthekey&login=3Dmyemail%40gmail.com>=0D=0A

I hope this helps!
I searched for a solution and ended up being more confused by the various suggestions as to the what the culprit was and how to go about fixing it. So hopefully this is a wise solution and I will have no more issues. If someone knows a problem with this fix and a better way please enlighten me.

Thanks!

#26 follow-up: @nicole2292
4 years ago

Hi everyone,

Why hasn't this been fixed in 5 years? (I'm on wordpress 4.9) I understand apparently this isn't a bug with wordpress, however if website customers cannot reset their password due to the code in the email sent by wordpress then that's a massive problem for businesses who use wordpress for their websites.

I'm working on a large site and they are having roughly 5 customer complaints per week from those who have tried a password reset and there was no link in the email they received. That's not really something which we can just ignore because it apparently isn't a bug...

As editing the core wordpress file wp-login.php is not an option (due to auto updates) I have written an override in the theme functions file:

<?php
//fix missing password reset link in emails
add_filter("retrieve_password_message", "custom_password_reset", 99, 4);

function custom_password_reset($message, $key, $user_login, $user_data )    {

    $message = __('Someone has requested a password reset for the following account:') . "<br><br>";
    $message .= network_home_url( '/' ) . "<br><br>";
    $message .= sprintf(__('%s'), $user_data->user_email) . "<br><br>";
    $message .= __('If this was a mistake, just ignore this email and nothing will happen.') . "<br><br>";
    $message .= __('To reset your password use the link below:') . "<br><br>";
    $message .= "<a href=".network_site_url("wp-login.php?action=rp&key=$key&login=" . rawurlencode($user_login), 'login') .">Click here to reset your password</a><br><br>";
    $message .= "Or copy and paste this link into your browser:<br><br>".network_site_url("wp-login.php?action=rp&key=$key&login=" . rawurlencode($user_login), 'login')."<br><br>";

    return $message;
}

The thing is that we should not have to use a plugin or write an override because the wordpress core files are not working as per the customers needs. The wordpress files should be correct for all customer email clients.

PLEASE PLEASE PLEASE fix this in the core.

Thank you very much,

Nicole

Last edited 4 years ago by nicole2292 (previous) (diff)

#27 @nagoke
4 years ago

Hi there,

I was facing a similar problem. Tried all suggestions as listed here but none worked.
Turns out, the customer-reset-password.php file in my child theme was somehow creating a conflict with the identical file in my parent theme. (yes, I don't understand how that can happen as both files are exactly the same!).
So, I deleted the customer-reset-password.php in my child theme and just like that, problem solved!

Hope this manages to help someone!
By the way, you can check out the link below which is where I got my answer from

https://wordpress.org/support/topic/missing-password-reset-link-in-email-with-storefront-enabled/

Regards

#28 @gavin@…
4 years ago

I was able to fix this by installing the Email Templates plugin
https://en-gb.wordpress.org/plugins/email-templates/

#29 @squarecandy
3 years ago

I also experienced this. Perhaps this is mainly a documentation issue as there is a pretty good solution using the filters already available. Here is what I ended up doing:

<?php
// adding support for html emails
// this converts ALL wp_mail emails to HTML, which messes up the password reset email
add_filter( 'wp_mail_content_type','squarecandy_set_content_type' );
function squarecandy_set_content_type() {
        return "text/html";
}

// add this filter too
// this will make the password reset email compatible with the HTML format
add_filter( 'retrieve_password_message', 'squarecandy_retrieve_password_message', 10, 2 );
function squarecandy_retrieve_password_message( $message ) {
        // Revise the message content to make it HTML email compatible
        $message = str_replace('<','',$message);
        $message = str_replace('>','',$message);
        $message = str_replace("\n",'<br>',$message);
        return $message;
}

The other solution is to adjust your wp_mail_content_type filter to only apply it to your custom emails. See https://wordpress.stackexchange.com/a/288159/41488

#30 in reply to: ↑ 26 @zammykoo
3 years ago

Replying to nicole2292:

Hi everyone,

Why hasn't this been fixed in 5 years? (I'm on wordpress 4.9) I understand apparently this isn't a bug with wordpress, however if website customers cannot reset their password due to the code in the email sent by wordpress then that's a massive problem for businesses who use wordpress for their websites.

I'm working on a large site and they are having roughly 5 customer complaints per week from those who have tried a password reset and there was no link in the email they received. That's not really something which we can just ignore because it apparently isn't a bug...

As editing the core wordpress file wp-login.php is not an option (due to auto updates) I have written an override in the theme functions file:

<?php
//fix missing password reset link in emails
add_filter("retrieve_password_message", "custom_password_reset", 99, 4);

function custom_password_reset($message, $key, $user_login, $user_data )    {

    $message = __('Someone has requested a password reset for the following account:') . "<br><br>";
    $message .= network_home_url( '/' ) . "<br><br>";
    $message .= sprintf(__('%s'), $user_data->user_email) . "<br><br>";
    $message .= __('If this was a mistake, just ignore this email and nothing will happen.') . "<br><br>";
    $message .= __('To reset your password use the link below:') . "<br><br>";
    $message .= "<a href=".network_site_url("wp-login.php?action=rp&key=$key&login=" . rawurlencode($user_login), 'login') .">Click here to reset your password</a><br><br>";
    $message .= "Or copy and paste this link into your browser:<br><br>".network_site_url("wp-login.php?action=rp&key=$key&login=" . rawurlencode($user_login), 'login')."<br><br>";

    return $message;
}

The thing is that we should not have to use a plugin or write an override because the wordpress core files are not working as per the customers needs. The wordpress files should be correct for all customer email clients.

PLEASE PLEASE PLEASE fix this in the core.

Thank you very much,

Nicole

Thank you Nicole! This worked for me.

#31 @sebastian.pisula
2 years ago

  • Keywords has-patch added; close removed
  • Resolution invalid deleted
  • Status changed from closed to reopened

The problem still exists. When I change globally content type to text/html.

@sebastian.pisula
2 years ago

Patch

#32 @eatingrules
21 months ago

  • Keywords needs-testing dev-feedback added

Thanks @sebastianpisula for submitting that patch. I completely agree, it's time to get rid of the < > brackets. The argument in favor of the brackets (#14140) was from 10 years ago, and at the time that was to help old email clients parse the link. Since then, there have been consistent reports that the brackets are parsed incorrectly by newer email clients, causing even more confusion and frustration.

#14140 (see Comment 7)
#30263
#23420

(We currently have this problem in HelpScout, since their system includes the trailing > in the link.)

At this point I think it would be better to remove the brackets, and have a valid, plain-text link (that a user of an old client might have to copy & paste), than to break the link on some modern email clients.

#33 @SergeyBiryukov
20 months ago

  • Owner set to SergeyBiryukov
  • Resolution set to fixed
  • Status changed from reopened to closed

In 47086:

Mail: Remove angle brackets from password reset URL in emails sent by retrieve_password() and wp_new_user_notification().

The brackets were originally added in [16285] per W3C recommendation in https://www.w3.org/Addressing/URL/5.1_Wrappers.html to avoid wrapping the URL across multiple lines in plain text in older email clients.

This doesn't seem like a common issue in modern email clients, and the current implementation causes more issues than it solves. Since the URL is on a line by itself, it should not require any delimiters.

The URL in recovery mode email introduced in [44973] doesn't have angle brackets, so it's time to retire them in password reset email too if they're not used consistently.

Props donmhico, Otto42, sproutchris, iandunn, dd32, DaveWP196, sebastian.pisula, tommix, sablednah, julian.kimmig, Rahe, clayisland, arenddeboer, nicole2292, nagoke, squarecandy, eatingrules, SergeyBiryukov.
Fixes #21095, #23578, #44589.

#34 @SergeyBiryukov
20 months ago

  • Milestone set to 5.4

#35 @nick-v
8 months ago

Hi,

I think closure of this ticket means that the last bullet here can be erased : https://developer.wordpress.org/reference/hooks/wp_mail_content_type/#more-information.

Thanks,

Note: See TracTickets for help on using tickets.