Mail: Improve handling of UTF-8 address headers.
Previously, `wp_mail()` implemented Reply-To as a generic header, using PHPMailer's `addCustomHeader()`. As such, the email address portion of the header was being incorrectly encoded when the name portion contained UTF-8 characters. Switching to PHPMailer's more specific `addReplyTo()` method fixes the issue. For greater readability, the handling of all address-related headers (To, CC, BCC, Reply-To) has been standardized. Props szepe.viktor, iandunn, bpetty, stephenharris. Fixes #21659. git-svn-id: https://develop.svn.wordpress.org/trunk@38058 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
parent
94c2212de8
commit
af068cdbe0
@ -216,6 +216,8 @@ function wp_mail( $to, $subject, $message, $headers = '', $attachments = array()
|
||||
}
|
||||
|
||||
// Headers
|
||||
$cc = $bcc = $reply_to = array();
|
||||
|
||||
if ( empty( $headers ) ) {
|
||||
$headers = array();
|
||||
} else {
|
||||
@ -227,8 +229,6 @@ function wp_mail( $to, $subject, $message, $headers = '', $attachments = array()
|
||||
$tempheaders = $headers;
|
||||
}
|
||||
$headers = array();
|
||||
$cc = array();
|
||||
$bcc = array();
|
||||
|
||||
// If it's actually got contents
|
||||
if ( !empty( $tempheaders ) ) {
|
||||
@ -291,6 +291,9 @@ function wp_mail( $to, $subject, $message, $headers = '', $attachments = array()
|
||||
case 'bcc':
|
||||
$bcc = array_merge( (array) $bcc, explode( ',', $content ) );
|
||||
break;
|
||||
case 'reply-to':
|
||||
$reply_to = array_merge( (array) $reply_to, explode( ',', $content ) );
|
||||
break;
|
||||
default:
|
||||
// Add it to our grand headers array
|
||||
$headers[trim( $name )] = trim( $content );
|
||||
@ -335,7 +338,7 @@ function wp_mail( $to, $subject, $message, $headers = '', $attachments = array()
|
||||
*
|
||||
* @param string $from_email Email address to send from.
|
||||
*/
|
||||
$phpmailer->From = apply_filters( 'wp_mail_from', $from_email );
|
||||
$from_email = apply_filters( 'wp_mail_from', $from_email );
|
||||
|
||||
/**
|
||||
* Filters the name to associate with the "from" email address.
|
||||
@ -344,63 +347,52 @@ function wp_mail( $to, $subject, $message, $headers = '', $attachments = array()
|
||||
*
|
||||
* @param string $from_name Name associated with the "from" email address.
|
||||
*/
|
||||
$phpmailer->FromName = apply_filters( 'wp_mail_from_name', $from_name );
|
||||
$from_name = apply_filters( 'wp_mail_from_name', $from_name );
|
||||
|
||||
$phpmailer->setFrom( $from_email, $from_name );
|
||||
|
||||
// Set destination addresses
|
||||
if ( !is_array( $to ) )
|
||||
$to = explode( ',', $to );
|
||||
|
||||
foreach ( (array) $to as $recipient ) {
|
||||
try {
|
||||
// Break $recipient into name and address parts if in the format "Foo <bar@baz.com>"
|
||||
$recipient_name = '';
|
||||
if ( preg_match( '/(.*)<(.+)>/', $recipient, $matches ) ) {
|
||||
if ( count( $matches ) == 3 ) {
|
||||
$recipient_name = $matches[1];
|
||||
$recipient = $matches[2];
|
||||
}
|
||||
}
|
||||
$phpmailer->AddAddress( $recipient, $recipient_name);
|
||||
} catch ( phpmailerException $e ) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Set mail's subject and body
|
||||
$phpmailer->Subject = $subject;
|
||||
$phpmailer->Body = $message;
|
||||
|
||||
// Add any CC and BCC recipients
|
||||
if ( !empty( $cc ) ) {
|
||||
foreach ( (array) $cc as $recipient ) {
|
||||
try {
|
||||
// Break $recipient into name and address parts if in the format "Foo <bar@baz.com>"
|
||||
$recipient_name = '';
|
||||
if ( preg_match( '/(.*)<(.+)>/', $recipient, $matches ) ) {
|
||||
if ( count( $matches ) == 3 ) {
|
||||
$recipient_name = $matches[1];
|
||||
$recipient = $matches[2];
|
||||
}
|
||||
}
|
||||
$phpmailer->AddCc( $recipient, $recipient_name );
|
||||
} catch ( phpmailerException $e ) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Use appropriate methods for handling addresses, rather than treating them as generic headers
|
||||
$address_headers = compact( 'to', 'cc', 'bcc', 'reply_to' );
|
||||
|
||||
if ( !empty( $bcc ) ) {
|
||||
foreach ( (array) $bcc as $recipient) {
|
||||
foreach ( $address_headers as $address_header => $addresses ) {
|
||||
if ( empty( $addresses ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ( (array) $addresses as $address ) {
|
||||
try {
|
||||
// Break $recipient into name and address parts if in the format "Foo <bar@baz.com>"
|
||||
$recipient_name = '';
|
||||
if ( preg_match( '/(.*)<(.+)>/', $recipient, $matches ) ) {
|
||||
|
||||
if ( preg_match( '/(.*)<(.+)>/', $address, $matches ) ) {
|
||||
if ( count( $matches ) == 3 ) {
|
||||
$recipient_name = $matches[1];
|
||||
$recipient = $matches[2];
|
||||
$address = $matches[2];
|
||||
}
|
||||
}
|
||||
$phpmailer->AddBcc( $recipient, $recipient_name );
|
||||
|
||||
switch ( $address_header ) {
|
||||
case 'to':
|
||||
$phpmailer->addAddress( $address, $recipient_name );
|
||||
break;
|
||||
case 'cc':
|
||||
$phpmailer->addCc( $address, $recipient_name );
|
||||
break;
|
||||
case 'bcc':
|
||||
$phpmailer->addBcc( $address, $recipient_name );
|
||||
break;
|
||||
case 'reply_to':
|
||||
$phpmailer->addReplyTo( $address, $recipient_name );
|
||||
break;
|
||||
}
|
||||
} catch ( phpmailerException $e ) {
|
||||
continue;
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ class MockPHPMailer extends PHPMailer {
|
||||
'to' => $this->to,
|
||||
'cc' => $this->cc,
|
||||
'bcc' => $this->bcc,
|
||||
'header' => $this->MIMEHeader,
|
||||
'header' => $this->MIMEHeader . $this->mailHeader,
|
||||
'subject' => $this->Subject,
|
||||
'body' => $this->MIMEBody,
|
||||
);
|
||||
|
@ -307,4 +307,39 @@ class Tests_Mail extends WP_UnitTestCase {
|
||||
|
||||
$this->assertNotContains( 'quoted-printable', $GLOBALS['phpmailer']->mock_sent[0]['header'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* @ticket 21659
|
||||
*/
|
||||
public function test_wp_mail_addresses_arent_encoded() {
|
||||
$to = 'Lukáš To <to@example.org>';
|
||||
$subject = 'Testing #21659';
|
||||
$message = 'Only the name should be encoded, not the address.';
|
||||
|
||||
$headers = array(
|
||||
'From' => 'From: Lukáš From <from@example.org>',
|
||||
'Cc' => 'Cc: Lukáš CC <cc@example.org>',
|
||||
'Bcc' => 'Bcc: Lukáš BCC <bcc@example.org>',
|
||||
'Reply-To' => 'Reply-To: Lukáš Reply-To <reply_to@example.org>',
|
||||
);
|
||||
|
||||
$expected = array(
|
||||
'To' => 'To: =?UTF-8?B?THVrw6HFoSBUbw==?= <to@example.org>',
|
||||
'From' => 'From: =?UTF-8?Q?Luk=C3=A1=C5=A1_From?= <from@example.org>',
|
||||
'Cc' => 'Cc: =?UTF-8?B?THVrw6HFoSBDQw==?= <cc@example.org>',
|
||||
'Bcc' => 'Bcc: =?UTF-8?B?THVrw6HFoSBCQ0M=?= <bcc@example.org>',
|
||||
'Reply-To' => 'Reply-To: =?UTF-8?Q?Luk=C3=A1=C5=A1_Reply-To?= <reply_to@example.org>',
|
||||
);
|
||||
|
||||
wp_mail( $to, $subject, $message, array_values( $headers ) );
|
||||
|
||||
$mailer = tests_retrieve_phpmailer_instance();
|
||||
$sent_headers = preg_split( "/\r\n|\n|\r/", $mailer->get_sent()->header );
|
||||
$headers['To'] = "To: $to";
|
||||
|
||||
foreach ( $headers as $header => $value ) {
|
||||
$target_headers = preg_grep( "/^$header:/", $sent_headers );
|
||||
$this->assertEquals( $expected[ $header ], array_pop( $target_headers ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user