Make WordPress Core

Ticket #29513: 29513-3-wpmail.3.diff

File 29513-3-wpmail.3.diff, 19.6 KB (added by stephenharris, 9 years ago)

Refreshed patch

  • new file src/wp-includes/class-wpmailer-factory.php

    diff --git src/wp-includes/class-wpmailer-factory.php src/wp-includes/class-wpmailer-factory.php
    new file mode 100644
    index 0000000..8f4917c
    - +  
     1<?php
     2
     3/**
     4 * Creates a WPMailer instance, and sets the default values of
     5 * the content type, charset and from name/email.
     6 *
     7 * @see WPMailer
     8 * @see wp_mail()
     9 */
     10class WPMailerFactory {
     11
     12        static function getMailer(){
     13
     14                require_once ABSPATH . WPINC . '/class-phpmailer.php';
     15                require_once ABSPATH . WPINC . '/class-wpmailer.php';
     16                require_once ABSPATH . WPINC . '/class-smtp.php';
     17
     18                $wpmailer = new WPMailer( true );
     19                $wpmailer = self::reset( $wpmailer );
     20
     21                return $wpmailer;
     22        }
     23
     24        static function reset( $wpmailer ){
     25
     26                $wpmailer->ClearAllRecipients();
     27                $wpmailer->ClearAttachments();
     28                $wpmailer->ClearCustomHeaders();
     29                $wpmailer->ClearReplyTos();
     30
     31                $sitename = strtolower( $_SERVER['SERVER_NAME'] );
     32                if ( substr( $sitename, 0, 4 ) == 'www.' ) {
     33                        $sitename = substr( $sitename, 4 );
     34                }
     35
     36        $wpmailer->ContentType = 'text/plain';
     37                $wpmailer->CharSet     = get_bloginfo( 'charset' );
     38
     39                $wpmailer->setFrom( 'wordpress@' . $sitename, 'WordPress' );
     40
     41                return $wpmailer;
     42        }
     43
     44}
     45?>
  • new file src/wp-includes/class-wpmailer.php

    diff --git src/wp-includes/class-wpmailer.php src/wp-includes/class-wpmailer.php
    new file mode 100644
    index 0000000..9d7c136
    - +  
     1<?php
     2/**
     3 * Email creation and transport class. (A child class of PHPMailer)
     4 *
     5 * This class adds a few 'helper' methods to the PHPMailer class and
     6 * overrides the send method to trigger e-mail related filters.
     7 *
     8 */
     9class WPMailer extends PHPMailer{
     10
     11        /**
     12         * Adds the passed e-mails as recipients
     13         *
     14         * @param string|array $recipients Array or comma-separated list of email addresses to send message.
     15         * @type string One of 'to', 'cc', 'bcc', or 'ReplyTo'
     16         */
     17        function addRecipients( $addresses, $type )  {
     18
     19                //Set destination addresses
     20                if ( !is_array( $addresses ) ){
     21                        $addresses = explode( ',', $addresses );
     22                }
     23
     24                foreach ( (array) $addresses as $address ) {
     25                        try {
     26                                // Break $recipient into name and address parts if in the format "Foo <bar@baz.com>"
     27                                $recipient_name = '';
     28
     29                                if ( preg_match( '/(.*)<(.+)>/', $address, $matches ) ) {
     30                                        if ( count( $matches ) == 3 ) {
     31                                                $recipient_name = $matches[1];
     32                                                $address        = $matches[2];
     33                                        }
     34                                }
     35
     36                                switch ( $type ) {
     37                                        case 'to':
     38                                                $this->addAddress( $address, $recipient_name );
     39                                                break;
     40                                        case 'cc':
     41                                                $this->addCc( $address, $recipient_name );
     42                                                break;
     43                                        case 'bcc':
     44                                                $this->addBcc( $address, $recipient_name );
     45                                                break;
     46                                        case 'reply_to':
     47                                                $this->addReplyTo( $address, $recipient_name );
     48                                                break;
     49                                }
     50                        } catch ( phpmailerException $e ) {
     51                                continue;
     52                        }
     53                }
     54        }
     55
     56        /**
     57         * Adds the provided headers to the e-mail.
     58         *
     59         * Will set the content type, charset and CC/BCC recipients where appropriate
     60         *
     61         * @param string|array $headers Additional headers.
     62         */
     63        function setHeaders( $headers = array() ){
     64
     65                $tempheaders = array();
     66
     67                // Headers
     68                if ( $headers ){
     69                        if ( !is_array( $headers ) ) {
     70                                // Explode the headers out, so this function can take both
     71                                // string headers and an array of headers.
     72                                $tempheaders = explode( "\n", str_replace( "\r\n", "\n", $headers ) );
     73                        } else {
     74                                $tempheaders = $headers;
     75                        }
     76                }
     77
     78                if ( empty( $tempheaders ) ) {
     79                        return;
     80                }
     81
     82                $headers = array();
     83                $cc = $bcc = $reply_to = array();
     84
     85
     86                // Iterate through the raw headers
     87                foreach ( (array) $tempheaders as $header ) {
     88                        if ( strpos($header, ':') === false ) {
     89                                if ( false !== stripos( $header, 'boundary=' ) ) {
     90                                        $parts = preg_split('/boundary=/i', trim( $header ) );
     91                                        $boundary = trim( str_replace( array( "'", '"' ), '', $parts[1] ) );
     92                                }
     93                                continue;
     94                        }
     95
     96                        // Explode them out
     97                        list( $name, $content ) = explode( ':', trim( $header ), 2 );
     98
     99                        // Cleanup crew
     100                        $name    = trim( $name    );
     101                        $content = trim( $content );
     102
     103                        switch ( strtolower( $name ) ):
     104                                // Mainly for legacy -- process a From: header if it's there
     105                                case 'from':
     106
     107                                        $bracket_pos = strpos( $content, '<' );
     108                                        if ( $bracket_pos !== false ) {
     109
     110                                                // Text before the bracketed email is the "From" name.
     111                                                if ( $bracket_pos > 0 ) {
     112                                                        $from_name = substr( $content, 0, $bracket_pos - 1 );
     113                                                        $from_name = str_replace( '"', '', $from_name );
     114                                                        $this->FromName = trim( $from_name );
     115                                                }
     116                                                $from_email = substr( $content, $bracket_pos + 1 );
     117                                                $from_email = str_replace( '>', '', $from_email );
     118                                                $this->From = trim( $from_email );
     119
     120                                                // Avoid setting an empty $from_email.
     121                                        } elseif ( '' !== trim( $content ) ) {
     122                                                $this->From = trim( $content );
     123                                        }
     124                                        break;
     125
     126                                case 'content-type':
     127
     128                                        if ( strpos( $content, ';' ) !== false ) {
     129
     130                                                list( $type, $charset_content ) = explode( ';', $content );
     131                                                $this->ContentType = trim( $type );
     132
     133                                                if ( false !== stripos( $charset_content, 'charset=' ) ) {
     134                                                        $this->CharSet = trim( str_replace( array( 'charset=', '"' ), '', $charset_content ) );
     135                                                } elseif ( false !== stripos( $charset_content, 'boundary=' ) ) {
     136                                                        $boundary = trim( str_replace( array( 'BOUNDARY=', 'boundary=', '"' ), '', $charset_content ) );
     137                                                        $charset = '';
     138                                                }
     139
     140                                                // Avoid setting an empty $content_type.
     141                                        } elseif ( '' !== trim( $content ) ) {
     142                                                $this->ContentType = trim( $content );
     143                                        }
     144
     145                                        if ( false !== stripos( $this->ContentType, 'multipart' ) && ! empty( $boundary ) ){
     146                                                $this->AddCustomHeader( sprintf( "Content-Type: %s;\n\t boundary=\"%s\"", $this->ContentType, $boundary ) );
     147                                        }
     148                                        break;
     149
     150                                case 'cc':
     151                                        $cc = array_merge( (array) $cc, explode( ',', $content ) );
     152                                        break;
     153
     154                                case 'bcc':
     155                                        $bcc = array_merge( (array) $bcc, explode( ',', $content ) );
     156                                        break;
     157                                case 'reply-to':
     158                                        $reply_to = array_merge( (array) $reply_to, explode( ',', $content ) );
     159                                        break;
     160                                default:
     161                                        // Add it to our grand headers array
     162                                        $this->AddCustomHeader( sprintf( '%1$s: %2$s', trim( $name ), trim( $content ) ) );
     163                                        break;
     164                        endswitch;
     165                }
     166
     167                // Use appropriate methods for handling addresses, rather than treating them as generic headers
     168                $address_headers = compact( 'cc', 'bcc', 'reply_to' );
     169
     170                foreach ( $address_headers as $address_header => $addresses ) {
     171                        if ( empty( $addresses ) ) {
     172                                continue;
     173                        }
     174
     175                        $this->addRecipients( $addresses, $address_header );
     176                }
     177        }
     178
     179        /**
     180         * Helper function for adding attachments.
     181         *
     182         * @param string|array $attachments Files to attach.
     183         */
     184        function addAttachments( $attachments ){
     185
     186                if ( !is_array($attachments) )
     187                        $attachments = explode( "\n", str_replace( "\r\n", "\n", $attachments ) );
     188
     189
     190                foreach ( (array) $attachments as $attachment ) {
     191                        try {
     192                                $this->AddAttachment( $attachment );
     193                        } catch ( phpmailerException $e ) {
     194                                continue;
     195                        }
     196                }
     197        }
     198
     199        /**
     200         * Pre-send routine, for "last minute" filtering of e-mail properties.
     201         *
     202         * Using the two 'wp_mail_from' and 'wp_mail_from_name' hooks allow from
     203         * creating a from address like 'Name <email@address.com>' when both are set. If
     204         * just 'wp_mail_from' is set, then just the email address will be used with no
     205         * name.
     206         *
     207         * The default content type is 'text/plain' which does not allow using HTML.
     208         * However, you can set the content type of the email by using the
     209         * 'wp_mail_content_type' filter.
     210         *
     211         * The default charset is based on the charset used on the blog. The charset can
     212         * be set using the 'wp_mail_charset' filter.
     213         *
     214         * @see PHPMailer::preSend();
     215         * @param string|array $attachments Files to attach.
     216         */
     217        function preSend(){
     218
     219                /**
     220                 * Filters the email address to send from.
     221                 *
     222                 * @since 2.2.0
     223                 *
     224                 * @param string $from_email Email address to send from.
     225                 */
     226                $from_email = apply_filters( 'wp_mail_from', $this->From );
     227
     228                /**
     229                 * Filters the name to associate with the "from" email address.
     230                 *
     231                 * @since 2.3.0
     232                 *
     233                 * @param string $from_name Name associated with the "from" email address.
     234                 */
     235                $from_name = apply_filters( 'wp_mail_from_name', $this->FromName );
     236
     237                $this->setFrom( $from_email, $from_name );
     238
     239                // Set to use PHP's mail()
     240                $this->IsMail();
     241
     242                /**
     243                * Filter the wp_mail() content type.
     244                *
     245                * @since 2.3.0
     246                *
     247                * @param string $content_type Default wp_mail() content type.
     248                */
     249                $this->ContentType = apply_filters( 'wp_mail_content_type', $this->ContentType );
     250
     251                // Set whether it's plaintext, depending on $content_type
     252                if ( 'text/html' == $this->ContentType ){
     253                        $this->IsHTML( true );
     254                }
     255
     256                /**
     257                * Filter the default wp_mail() charset.
     258                *
     259                * @since 2.3.0
     260                *
     261                * @param string $charset Default email charset.
     262                */
     263                $this->CharSet = apply_filters( 'wp_mail_charset', $this->CharSet );
     264
     265                /**
     266                * Fires after PHPMailer is initialized.
     267                *
     268                * @since 2.2.0
     269                *
     270                * @param PHPMailer &$this The PHPMailer instance, passed by reference.
     271                */
     272                do_action_ref_array( 'phpmailer_init', array( &$this ) );
     273
     274                return parent::preSend();
     275
     276        }
     277
     278}
  • src/wp-includes/pluggable.php

    diff --git src/wp-includes/pluggable.php src/wp-includes/pluggable.php
    index 511e6ac..3935efa 100644
    if ( !function_exists( 'wp_mail' ) ) : 
    147147 * email successfully. It just only means that the method used was able to
    148148 * process the request without any errors.
    149149 *
    150  * Using the two 'wp_mail_from' and 'wp_mail_from_name' hooks allow from
    151  * creating a from address like 'Name <email@address.com>' when both are set. If
    152  * just 'wp_mail_from' is set, then just the email address will be used with no
    153  * name.
    154  *
    155  * The default content type is 'text/plain' which does not allow using HTML.
    156  * However, you can set the content type of the email by using the
    157  * {@see 'wp_mail_content_type'} filter.
    158  *
    159  * The default charset is based on the charset used on the blog. The charset can
    160  * be set using the {@see 'wp_mail_charset'} filter.
    161  *
    162150 * @since 1.2.1
    163151 *
    164  * @global PHPMailer $phpmailer
     152 * @uses WPMailer
    165153 *
    166154 * @param string|array $to          Array or comma-separated list of email addresses to send message.
    167155 * @param string       $subject     Email subject
    function wp_mail( $to, $subject, $message, $headers = '', $attachments = array() 
    203191                $attachments = $atts['attachments'];
    204192        }
    205193
    206         if ( ! is_array( $attachments ) ) {
    207                 $attachments = explode( "\n", str_replace( "\r\n", "\n", $attachments ) );
    208         }
    209194        global $phpmailer;
    210195
    211196        // (Re)create it, if it's gone missing
    212         if ( ! ( $phpmailer instanceof PHPMailer ) ) {
    213                 require_once ABSPATH . WPINC . '/class-phpmailer.php';
    214                 require_once ABSPATH . WPINC . '/class-smtp.php';
    215                 $phpmailer = new PHPMailer( true );
    216         }
    217 
    218         // Headers
    219         $cc = $bcc = $reply_to = array();
    220 
    221         if ( empty( $headers ) ) {
    222                 $headers = array();
     197        if ( ! is_object( $phpmailer ) || ! is_a( $phpmailer, 'WPMailer' ) ) {
     198                $phpmailer = WPMailerFactory::getMailer();
    223199        } else {
    224                 if ( !is_array( $headers ) ) {
    225                         // Explode the headers out, so this function can take both
    226                         // string headers and an array of headers.
    227                         $tempheaders = explode( "\n", str_replace( "\r\n", "\n", $headers ) );
    228                 } else {
    229                         $tempheaders = $headers;
    230                 }
    231                 $headers = array();
    232 
    233                 // If it's actually got contents
    234                 if ( !empty( $tempheaders ) ) {
    235                         // Iterate through the raw headers
    236                         foreach ( (array) $tempheaders as $header ) {
    237                                 if ( strpos($header, ':') === false ) {
    238                                         if ( false !== stripos( $header, 'boundary=' ) ) {
    239                                                 $parts = preg_split('/boundary=/i', trim( $header ) );
    240                                                 $boundary = trim( str_replace( array( "'", '"' ), '', $parts[1] ) );
    241                                         }
    242                                         continue;
    243                                 }
    244                                 // Explode them out
    245                                 list( $name, $content ) = explode( ':', trim( $header ), 2 );
    246 
    247                                 // Cleanup crew
    248                                 $name    = trim( $name    );
    249                                 $content = trim( $content );
    250 
    251                                 switch ( strtolower( $name ) ) {
    252                                         // Mainly for legacy -- process a From: header if it's there
    253                                         case 'from':
    254                                                 $bracket_pos = strpos( $content, '<' );
    255                                                 if ( $bracket_pos !== false ) {
    256                                                         // Text before the bracketed email is the "From" name.
    257                                                         if ( $bracket_pos > 0 ) {
    258                                                                 $from_name = substr( $content, 0, $bracket_pos - 1 );
    259                                                                 $from_name = str_replace( '"', '', $from_name );
    260                                                                 $from_name = trim( $from_name );
    261                                                         }
    262 
    263                                                         $from_email = substr( $content, $bracket_pos + 1 );
    264                                                         $from_email = str_replace( '>', '', $from_email );
    265                                                         $from_email = trim( $from_email );
    266 
    267                                                 // Avoid setting an empty $from_email.
    268                                                 } elseif ( '' !== trim( $content ) ) {
    269                                                         $from_email = trim( $content );
    270                                                 }
    271                                                 break;
    272                                         case 'content-type':
    273                                                 if ( strpos( $content, ';' ) !== false ) {
    274                                                         list( $type, $charset_content ) = explode( ';', $content );
    275                                                         $content_type = trim( $type );
    276                                                         if ( false !== stripos( $charset_content, 'charset=' ) ) {
    277                                                                 $charset = trim( str_replace( array( 'charset=', '"' ), '', $charset_content ) );
    278                                                         } elseif ( false !== stripos( $charset_content, 'boundary=' ) ) {
    279                                                                 $boundary = trim( str_replace( array( 'BOUNDARY=', 'boundary=', '"' ), '', $charset_content ) );
    280                                                                 $charset = '';
    281                                                         }
    282 
    283                                                 // Avoid setting an empty $content_type.
    284                                                 } elseif ( '' !== trim( $content ) ) {
    285                                                         $content_type = trim( $content );
    286                                                 }
    287                                                 break;
    288                                         case 'cc':
    289                                                 $cc = array_merge( (array) $cc, explode( ',', $content ) );
    290                                                 break;
    291                                         case 'bcc':
    292                                                 $bcc = array_merge( (array) $bcc, explode( ',', $content ) );
    293                                                 break;
    294                                         case 'reply-to':
    295                                                 $reply_to = array_merge( (array) $reply_to, explode( ',', $content ) );
    296                                                 break;
    297                                         default:
    298                                                 // Add it to our grand headers array
    299                                                 $headers[trim( $name )] = trim( $content );
    300                                                 break;
    301                                 }
    302                         }
    303                 }
    304         }
    305 
    306         // Empty out the values that may be set
    307         $phpmailer->ClearAllRecipients();
    308         $phpmailer->ClearAttachments();
    309         $phpmailer->ClearCustomHeaders();
    310         $phpmailer->ClearReplyTos();
    311 
    312         // From email and name
    313         // If we don't have a name from the input headers
    314         if ( !isset( $from_name ) )
    315                 $from_name = 'WordPress';
    316 
    317         /* If we don't have an email from the input headers default to wordpress@$sitename
    318          * Some hosts will block outgoing mail from this address if it doesn't exist but
    319          * there's no easy alternative. Defaulting to admin_email might appear to be another
    320          * option but some hosts may refuse to relay mail from an unknown domain. See
    321          * https://core.trac.wordpress.org/ticket/5007.
    322          */
    323 
    324         if ( !isset( $from_email ) ) {
    325                 // Get the site domain and get rid of www.
    326                 $sitename = strtolower( $_SERVER['SERVER_NAME'] );
    327                 if ( substr( $sitename, 0, 4 ) == 'www.' ) {
    328                         $sitename = substr( $sitename, 4 );
    329                 }
    330 
    331                 $from_email = 'wordpress@' . $sitename;
     200                $phpmailer = WPMailerFactory::reset( $phpmailer );
    332201        }
    333202
    334         /**
    335          * Filters the email address to send from.
    336          *
    337          * @since 2.2.0
    338          *
    339          * @param string $from_email Email address to send from.
    340          */
    341         $from_email = apply_filters( 'wp_mail_from', $from_email );
    342 
    343         /**
    344          * Filters the name to associate with the "from" email address.
    345          *
    346          * @since 2.3.0
    347          *
    348          * @param string $from_name Name associated with the "from" email address.
    349          */
    350         $from_name = apply_filters( 'wp_mail_from_name', $from_name );
    351 
    352         $phpmailer->setFrom( $from_email, $from_name );
    353 
    354203        // Set destination addresses
    355         if ( !is_array( $to ) )
    356                 $to = explode( ',', $to );
     204        $phpmailer->addRecipients( $to, 'to' );
    357205
    358206        // Set mail's subject and body
    359207        $phpmailer->Subject = $subject;
    360208        $phpmailer->Body    = $message;
    361209
    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 ) {
    371                         try {
    372                                 // Break $recipient into name and address parts if in the format "Foo <bar@baz.com>"
    373                                 $recipient_name = '';
    374 
    375                                 if ( preg_match( '/(.*)<(.+)>/', $address, $matches ) ) {
    376                                         if ( count( $matches ) == 3 ) {
    377                                                 $recipient_name = $matches[1];
    378                                                 $address        = $matches[2];
    379                                         }
    380                                 }
    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;
    395                                 }
    396                         } catch ( phpmailerException $e ) {
    397                                 continue;
    398                         }
    399                 }
    400         }
    401 
    402         // Set to use PHP's mail()
    403         $phpmailer->IsMail();
    404 
    405         // Set Content-Type and charset
    406         // If we don't have a content-type from the input headers
    407         if ( !isset( $content_type ) )
    408                 $content_type = 'text/plain';
    409 
    410         /**
    411          * Filters the wp_mail() content type.
    412          *
    413          * @since 2.3.0
    414          *
    415          * @param string $content_type Default wp_mail() content type.
    416          */
    417         $content_type = apply_filters( 'wp_mail_content_type', $content_type );
    418 
    419         $phpmailer->ContentType = $content_type;
    420 
    421         // Set whether it's plaintext, depending on $content_type
    422         if ( 'text/html' == $content_type )
    423                 $phpmailer->IsHTML( true );
    424 
    425         // If we don't have a charset from the input headers
    426         if ( !isset( $charset ) )
    427                 $charset = get_bloginfo( 'charset' );
    428 
    429         // Set the content-type and charset
    430 
    431         /**
    432          * Filters the default wp_mail() charset.
    433          *
    434          * @since 2.3.0
    435          *
    436          * @param string $charset Default email charset.
    437          */
    438         $phpmailer->CharSet = apply_filters( 'wp_mail_charset', $charset );
    439 
    440210        // Set custom headers
    441211        if ( !empty( $headers ) ) {
    442                 foreach ( (array) $headers as $name => $content ) {
    443                         $phpmailer->AddCustomHeader( sprintf( '%1$s: %2$s', $name, $content ) );
    444                 }
    445 
    446                 if ( false !== stripos( $content_type, 'multipart' ) && ! empty($boundary) )
    447                         $phpmailer->AddCustomHeader( sprintf( "Content-Type: %s;\n\t boundary=\"%s\"", $content_type, $boundary ) );
     212                $phpmailer->setHeaders( $headers );
    448213        }
    449214
    450         if ( !empty( $attachments ) ) {
    451                 foreach ( $attachments as $attachment ) {
    452                         try {
    453                                 $phpmailer->AddAttachment($attachment);
    454                         } catch ( phpmailerException $e ) {
    455                                 continue;
    456                         }
    457                 }
    458         }
    459 
    460         /**
    461          * Fires after PHPMailer is initialized.
    462          *
    463          * @since 2.2.0
    464          *
    465          * @param PHPMailer &$phpmailer The PHPMailer instance, passed by reference.
    466          */
    467         do_action_ref_array( 'phpmailer_init', array( &$phpmailer ) );
     215        //Set attachments
     216        $phpmailer->addAttachments( $attachments );
    468217
    469218        // Send!
    470219        try {
  • src/wp-settings.php

    diff --git src/wp-settings.php src/wp-settings.php
    index 37a31c2..8eeb043 100644
    require( ABSPATH . WPINC . '/rest-api.php' ); 
    213213require( ABSPATH . WPINC . '/rest-api/class-wp-rest-server.php' );
    214214require( ABSPATH . WPINC . '/rest-api/class-wp-rest-response.php' );
    215215require( ABSPATH . WPINC . '/rest-api/class-wp-rest-request.php' );
     216require( ABSPATH . WPINC . '/class-wpmailer-factory.php' );
    216217
    217218// Load multisite-specific files.
    218219if ( is_multisite() ) {
  • tests/phpunit/includes/mock-mailer.php

    diff --git tests/phpunit/includes/mock-mailer.php tests/phpunit/includes/mock-mailer.php
    index 7acfd57..940792c 100644
     
    11<?php
    22require_once( ABSPATH . '/wp-includes/class-phpmailer.php' );
     3require_once( ABSPATH . '/wp-includes/class-wpmailer.php' );
    34
    4 class MockPHPMailer extends PHPMailer {
     5class MockPHPMailer extends WPMailer {
    56        var $mock_sent = array();
    67
    78        function preSend() {