WordPress.org

Make WordPress Core


Ignore:
Timestamp:
07/13/2016 06:03:52 PM (23 months ago)
Author:
boonebgorges
Message:

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.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/pluggable.php

    r38028 r38058  
    217217
    218218    // Headers
     219    $cc = $bcc = $reply_to = array();
     220
    219221    if ( empty( $headers ) ) {
    220222        $headers = array();
     
    228230        }
    229231        $headers = array();
    230         $cc = array();
    231         $bcc = array();
    232232
    233233        // If it's actually got contents
     
    292292                        $bcc = array_merge( (array) $bcc, explode( ',', $content ) );
    293293                        break;
     294                    case 'reply-to':
     295                        $reply_to = array_merge( (array) $reply_to, explode( ',', $content ) );
     296                        break;
    294297                    default:
    295298                        // Add it to our grand headers array
     
    336339     * @param string $from_email Email address to send from.
    337340     */
    338     $phpmailer->From = apply_filters( 'wp_mail_from', $from_email );
     341    $from_email = apply_filters( 'wp_mail_from', $from_email );
    339342
    340343    /**
     
    345348     * @param string $from_name Name associated with the "from" email address.
    346349     */
    347     $phpmailer->FromName = apply_filters( 'wp_mail_from_name', $from_name );
     350    $from_name = apply_filters( 'wp_mail_from_name', $from_name );
     351
     352    $phpmailer->setFrom( $from_email, $from_name );
    348353
    349354    // Set destination addresses
     
    351356        $to = explode( ',', $to );
    352357
    353     foreach ( (array) $to as $recipient ) {
    354         try {
    355             // Break $recipient into name and address parts if in the format "Foo <bar@baz.com>"
    356             $recipient_name = '';
    357             if ( preg_match( '/(.*)<(.+)>/', $recipient, $matches ) ) {
    358                 if ( count( $matches ) == 3 ) {
    359                     $recipient_name = $matches[1];
    360                     $recipient = $matches[2];
    361                 }
    362             }
    363             $phpmailer->AddAddress( $recipient, $recipient_name);
    364         } catch ( phpmailerException $e ) {
    365             continue;
    366         }
    367     }
    368 
    369358    // Set mail's subject and body
    370359    $phpmailer->Subject = $subject;
    371360    $phpmailer->Body    = $message;
    372361
    373     // Add any CC and BCC recipients
    374     if ( !empty( $cc ) ) {
    375         foreach ( (array) $cc as $recipient ) {
     362    // Use appropriate methods for handling addresses, rather than treating them as generic headers
     363    $address_headers = compact( 'to', 'cc', 'bcc', 'reply_to' );
     364
     365    foreach ( $address_headers as $address_header => $addresses ) {
     366        if ( empty( $addresses ) ) {
     367            continue;
     368        }
     369
     370        foreach ( (array) $addresses as $address ) {
    376371            try {
    377372                // Break $recipient into name and address parts if in the format "Foo <bar@baz.com>"
    378373                $recipient_name = '';
    379                 if ( preg_match( '/(.*)<(.+)>/', $recipient, $matches ) ) {
     374
     375                if ( preg_match( '/(.*)<(.+)>/', $address, $matches ) ) {
    380376                    if ( count( $matches ) == 3 ) {
    381377                        $recipient_name = $matches[1];
    382                         $recipient = $matches[2];
     378                        $address        = $matches[2];
    383379                    }
    384380                }
    385                 $phpmailer->AddCc( $recipient, $recipient_name );
    386             } catch ( phpmailerException $e ) {
    387                 continue;
    388             }
    389         }
    390     }
    391 
    392     if ( !empty( $bcc ) ) {
    393         foreach ( (array) $bcc as $recipient) {
    394             try {
    395                 // Break $recipient into name and address parts if in the format "Foo <bar@baz.com>"
    396                 $recipient_name = '';
    397                 if ( preg_match( '/(.*)<(.+)>/', $recipient, $matches ) ) {
    398                     if ( count( $matches ) == 3 ) {
    399                         $recipient_name = $matches[1];
    400                         $recipient = $matches[2];
    401                     }
     381
     382                switch ( $address_header ) {
     383                    case 'to':
     384                        $phpmailer->addAddress( $address, $recipient_name );
     385                        break;
     386                    case 'cc':
     387                        $phpmailer->addCc( $address, $recipient_name );
     388                        break;
     389                    case 'bcc':
     390                        $phpmailer->addBcc( $address, $recipient_name );
     391                        break;
     392                    case 'reply_to':
     393                        $phpmailer->addReplyTo( $address, $recipient_name );
     394                        break;
    402395                }
    403                 $phpmailer->AddBcc( $recipient, $recipient_name );
    404396            } catch ( phpmailerException $e ) {
    405397                continue;
Note: See TracChangeset for help on using the changeset viewer.