diff --git a/src/wp-includes/pluggable.php b/src/wp-includes/pluggable.php index 5edd0c760cbb2..52e11d41542fa 100644 --- a/src/wp-includes/pluggable.php +++ b/src/wp-includes/pluggable.php @@ -351,6 +351,9 @@ function wp_mail( $to, $subject, $message, $headers = '', $attachments = array() } elseif ( false !== stripos( $charset_content, 'boundary=' ) ) { $boundary = trim( str_replace( array( 'BOUNDARY=', 'boundary=', '"' ), '', $charset_content ) ); $charset = ''; + if ( preg_match( '~multipart/([a-z]+)~i', $content_type, $matches ) ) { + $content_type = 'multipart/' . strtolower( $matches[1] ) . '; boundary="' . $boundary . '"'; + } } // Avoid setting an empty $content_type. @@ -538,10 +541,6 @@ function wp_mail( $to, $subject, $message, $headers = '', $attachments = array() } } } - - if ( false !== stripos( $content_type, 'multipart' ) && ! empty( $boundary ) ) { - $phpmailer->addCustomHeader( sprintf( 'Content-Type: %s; boundary="%s"', $content_type, $boundary ) ); - } } if ( ! empty( $attachments ) ) { diff --git a/tests/phpunit/tests/pluggable/wpMail.php b/tests/phpunit/tests/pluggable/wpMail.php index ee0c2ea0f0d8f..0f0127abf0521 100644 --- a/tests/phpunit/tests/pluggable/wpMail.php +++ b/tests/phpunit/tests/pluggable/wpMail.php @@ -83,7 +83,7 @@ public function test_wp_mail_custom_boundaries() { // We need some better assertions here but these catch the failure for now. $this->assertSameIgnoreEOL( $body, $mailer->get_sent()->body ); - $this->assertStringContainsString( 'boundary="----=_Part_4892_25692638.1192452070893"', iconv_mime_decode_headers( ( $mailer->get_sent()->header ) )['Content-Type'][0] ); + $this->assertStringContainsString( 'boundary="----=_Part_4892_25692638.1192452070893"', $mailer->get_sent()->header ); $this->assertStringContainsString( 'charset=', $mailer->get_sent()->header ); } @@ -626,4 +626,90 @@ public function test_wp_mail_string_embeds() { $this->assertStringContainsString( 'cid:' . $key, $mailer->get_sent()->body, 'The cid ' . $key . ' is not referenced in the mail body.' ); } } + + /** + * Test that wp_mail() can send a multipart/alternative email with plain text and html versions. + * + * @ticket 15448 + */ + public function test_wp_mail_plain_and_html() { + $headers = 'Content-Type: multipart/alternative; boundary="TestBoundary"'; + $to = 'user@example.com'; + $subject = 'Test email with plain text and html versions'; + $message = <<Here is the HTML with UTF-8 γειά σου Κόσμε;-) +--TestBoundary-- +EOT; + + wp_mail( $to, $subject, $message, $headers ); + $mailer = tests_retrieve_phpmailer_instance(); + + preg_match( '/boundary="(.*)"/', $mailer->get_sent()->header, $matches ); + $boundary = $matches[1]; + $body = '--' . $boundary . "\n"; + $body .= 'Content-Type: text/plain; charset=us-ascii' . "\n"; + $body .= "\n"; + $body .= 'Here is some plain text.' . "\n"; + $body .= '--' . $boundary . "\n"; + $body .= 'Content-Type: text/html; charset=UTF-8' . "\n"; + $body .= 'Content-Transfer-Encoding: 8bit' . "\n"; + $body .= "\n"; + $body .= 'Here is the HTML with UTF-8 γειά σου Κόσμε;-)' . "\n"; + $body .= '--' . $boundary . '--' . "\n"; + + $this->assertSameIgnoreEOL( $body, $mailer->get_sent()->body, 'The body is not as expected.' ); + $this->assertStringContainsString( + 'Content-Type: multipart/alternative;', + $mailer->get_sent()->header, + 'The multipart/alternative header is not present.' + ); + } + + /* + * 'phpmailer_init' action for test_wp_mail_plain_and_html_workaround(). + */ + public function wp_mail_set_alt_body( $mailer ) { + $mailer->AltBody = strip_tags( $mailer->Body ); + } + + /** + * Check workarounds using phpmailer_init still work around. + * + * @ticket 15448 + */ + public function test_wp_mail_plain_and_html_workaround() { + $to = 'user@example.com'; + $subject = 'Test email with plain text derived from html version'; + $message = '

Hello World! γειά σου Κόσμε

'; + + add_action( 'phpmailer_init', array( $this, 'wp_mail_set_alt_body' ) ); + wp_mail( $to, $subject, $message ); + remove_action( 'phpmailer_init', array( $this, 'wp_mail_set_alt_body' ) ); + + $mailer = tests_retrieve_phpmailer_instance(); + + $this->assertStringContainsString( + 'Content-Type: multipart/alternative;', + $mailer->get_sent()->header, + 'The multipart/alternative header is not present.' + ); + $this->assertStringContainsString( + 'Content-Type: text/plain; charset=UTF-8', + $mailer->get_sent()->body, + 'The text/plain Content-Type header is not present.' + ); + $this->assertStringContainsString( + 'Content-Type: text/html; charset=UTF-8', + $mailer->get_sent()->body, + 'The text/html Content-Type header is not present.' + ); + } }