2

Is there a way to change the content type for only the password reset email?

I have a custom HTML template for it, and have set wp_mail_content_type to text/html and am applying the template with a filter on retrieve_password_message. That all works fine and I get an HTML email for it, but I’m having a hard time figuring out where/how to reset wp_mail_content_type since I’m not actually calling wp_mail() anywhere.

Any help would be greatly appreciated.

EDIT - here’s the code I’m using.

This is the function that changes the content type:

function xxx_wp_email_content_type() {
    return 'text/html';
}
add_filter( 'wp_mail_content_type', 'xxx_wp_email_content_type' );

And here’s the function that changes the email itself:

function xxx_wp_retrieve_password_message( $content, $key ) {
    ob_start();

    $email_subject = xxx_wp_retrieve_password_title();

    include( 'templates/email_header.php' );
    include( 'templates/lost_password_email.php' );
    include( 'templates/email_footer.php' );

    $message = ob_get_contents();
    ob_end_clean();

    return $message;
}
add_filter( 'retrieve_password_message', 'xxx_wp_retrieve_password_message', 10, 2 );

Typically I’d add a remove_filter( 'wp_mail_content_type', 'xxx_wp_email_content_type' ); after a call to wp_mail(), but there isn’t one here.

4
  • Can you provide an example of your code and how you're using the filters?
    – phatskat
    Dec 8, 2017 at 19:18
  • Did not quite follow. Why do you need to reset the wp_mail_content_type, is it because you want other emails to send as text only?
    – signal2013
    Dec 8, 2017 at 19:27
  • @signal2013 Yes, the only one I want to send as HTML is the password reset email.
    – jmock
    Dec 8, 2017 at 21:35
  • @phatskat Code has been added.
    – jmock
    Dec 8, 2017 at 21:45

4 Answers 4

2

I suspect you implemented the hook something like this:

function wp_set_html_mail_content_type() {
    return 'text/html';
}
add_filter( 'wp_mail_content_type', 'wp_set_html_mail_content_type' );

More info: https://codex.wordpress.org/Plugin_API/Filter_Reference/wp_mail_content_type

Did you need to reset the content type at a later point?


** UPDATE: try intercept it with a global variable:

function xxx_wp_email_content_type() {
    if($GLOBALS["use_html_content_type"]){
        return 'text/html';
    }else{
        return 'text/plain';
    }
}
add_filter( 'wp_mail_content_type', 'xxx_wp_email_content_type' );

function xxx_wp_retrieve_password_message( $content, $key ) {
    ob_start();

    $GLOBALS["use_html_content_type"] = TRUE;

    $email_subject = xxx_wp_retrieve_password_title();

    include( 'templates/email_header.php' );
    include( 'templates/lost_password_email.php' );
    include( 'templates/email_footer.php' );

    $message = ob_get_contents();
    ob_end_clean();

    return $message;
}
add_filter( 'retrieve_password_message', 'xxx_wp_retrieve_password_message', 10, 2 );
3
  • That’s correct... that’s how I’m doing it. The part I’m having trouble figuring out is how to reset it to text/plain since I don’t want the other emails sent as HTML because they don’t have line breaks, etc. when they are set to HTML.
    – jmock
    Dec 8, 2017 at 21:38
  • Ok, you could try intercept it with a global variable... I updated the snippet above.
    – signal2013
    Dec 8, 2017 at 22:14
  • Thanks! It seems to be working during initial testing. I still need to test a bit more, but it’s looking good so far.
    – jmock
    Dec 8, 2017 at 22:36
1

This way works for me without setting a $GLOBAL:

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

function xxx_wp_retrieve_password_message( $content, $key ) {
    add_filter( 'wp_mail_content_type', 'xxx_wp_email_content_type' );

    ob_start();

    $email_subject = xxx_wp_retrieve_password_title();

    include( 'templates/email_header.php' );
    include( 'templates/lost_password_email.php' );
    include( 'templates/email_footer.php' );

    $message = ob_get_contents();
    ob_end_clean();

    return $message;
}
add_filter( 'retrieve_password_message', 'xxx_wp_retrieve_password_message', 10, 2 );
1

Since Wordpress 6.0 you can use the retrieve_password_notification_email to access (among other things) the headers for only the lost password email:

function set_lost_password_email_content_type(array $defaults, string $key, string $user_login, WP_User $user_data): array
{
    if (!isset($defaults['headers'])) {
        $defaults['headers'] = [];
    }

    $defaults['headers'] = (array) $defaults['headers'];

    $defaults['headers'][] = 'Content-Type: text/html';

    return $defaults;
}

add_filter(
    'retrieve_password_notification_email',
    'set_lost_password_email_content_type',
    10,
    4
);

The filter is called in wp-includes/user.php:

/**
 * Filters the contents of the reset password notification email sent to the user.
 *
 * @since 6.0.0
 *
 * @param array $defaults {
 *     The default notification email arguments. Used to build wp_mail().
 *
 *     @type string $to      The intended recipient - user email address.
 *     @type string $subject The subject of the email.
 *     @type string $message The body of the email.
 *     @type string $headers The headers of the email.
 * }
 * @type string  $key        The activation key.
 * @type string  $user_login The username for the user.
 * @type WP_User $user_data  WP_User object.
 */
$notification_email = apply_filters( 'retrieve_password_notification_email', $defaults, $key, $user_login, $user_data );
0

This doesn't technically answer the question - but more the question behind the question. The reason you might want to set the content type only for the password reset email is that setting all system emails to text/html will break the default password reset email.

I suggest using the retrieve_password_message filter in combination with the wp_mail_content_type filter to make the password reset email compatible with the HTML format:

<?php
// adding support for html emails
// this converts ALL wp_mail emails to HTML, which messes up the password reset
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, 1 );
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);
    // make any additional modifications to the message here...
    return $message;
}

Otherwise, if you only want to set individual emails to text/html, the $GLOBALS method in the answer from @signal2013 also works, but might be better applied to target your custom email instead of to the default password reset email (leave this as the default text/plain).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.