diff --git a/src/wp-includes/pluggable.php b/src/wp-includes/pluggable.php
index 9336e03c7e..09ec4503db 100644
--- a/src/wp-includes/pluggable.php
+++ b/src/wp-includes/pluggable.php
@@ -153,6 +153,11 @@ if ( ! function_exists( 'wp_mail' ) ) :
 	 * However, you can set the content type of the email by using the
 	 * {@see 'wp_mail_content_type'} filter.
 	 *
+	 * If $message is an array, the key of each is used to add as an attachment
+	 * with the value used as the body. The 'text/plain' element is used as the
+	 * text version of the body, with the 'text/html' element used as the HTML
+	 * version of the body. All other types are added as attachments.
+	 *
 	 * The default charset is based on the charset used on the blog. The charset can
 	 * be set using the {@see 'wp_mail_charset'} filter.
 	 *
@@ -162,7 +167,7 @@ if ( ! function_exists( 'wp_mail' ) ) :
 	 *
 	 * @param string|array $to          Array or comma-separated list of email addresses to send message.
 	 * @param string       $subject     Email subject
-	 * @param string       $message     Message contents
+	 * @param string|array $message     Message contents
 	 * @param string|array $headers     Optional. Additional headers.
 	 * @param string|array $attachments Optional. Files to attach.
 	 * @return bool Whether the email contents were sent successfully.
@@ -273,6 +278,10 @@ if ( ! function_exists( 'wp_mail' ) ) :
 							}
 							break;
 						case 'content-type':
+							if ( is_array( $message ) ) {
+								// Multipart email, ignore the content-type header
+								break;
+							}
 							if ( strpos( $content, ';' ) !== false ) {
 								list( $type, $charset_content ) = explode( ';', $content );
 								$content_type                   = trim( $type );
@@ -312,6 +321,9 @@ if ( ! function_exists( 'wp_mail' ) ) :
 		$phpmailer->clearCustomHeaders();
 		$phpmailer->clearReplyTos();
 
+		$phpmailer->Body= '';
+		$phpmailer->AltBody= '';
+
 		// From email and name
 		// If we don't have a name from the input headers
 		if ( ! isset( $from_name ) ) {
@@ -365,10 +377,6 @@ if ( ! function_exists( 'wp_mail' ) ) :
 			return false;
 		}
 
-		// Set mail's subject and body
-		$phpmailer->Subject = $subject;
-		$phpmailer->Body    = $message;
-
 		// Set destination addresses, using appropriate methods for handling addresses
 		$address_headers = compact( 'to', 'cc', 'bcc', 'reply_to' );
 
@@ -409,38 +417,12 @@ if ( ! function_exists( 'wp_mail' ) ) :
 			}
 		}
 
-		// Set to use PHP's mail()
-		$phpmailer->isMail();
-
-		// Set Content-Type and charset
-		// If we don't have a content-type from the input headers
-		if ( ! isset( $content_type ) ) {
-			$content_type = 'text/plain';
-		}
-
-		/**
-		 * Filters the wp_mail() content type.
-		 *
-		 * @since 2.3.0
-		 *
-		 * @param string $content_type Default wp_mail() content type.
-		 */
-		$content_type = apply_filters( 'wp_mail_content_type', $content_type );
-
-		$phpmailer->ContentType = $content_type;
-
-		// Set whether it's plaintext, depending on $content_type
-		if ( 'text/html' == $content_type ) {
-			$phpmailer->isHTML( true );
-		}
-
+		// Set a charset
 		// If we don't have a charset from the input headers
 		if ( ! isset( $charset ) ) {
 			$charset = get_bloginfo( 'charset' );
 		}
 
-		// Set the content-type and charset
-
 		/**
 		 * Filters the default wp_mail() charset.
 		 *
@@ -450,15 +432,61 @@ if ( ! function_exists( 'wp_mail' ) ) :
 		 */
 		$phpmailer->CharSet = apply_filters( 'wp_mail_charset', $charset );
 
-		// Set custom headers
-		if ( ! empty( $headers ) ) {
-			foreach ( (array) $headers as $name => $content ) {
-				$phpmailer->addCustomHeader( sprintf( '%1$s: %2$s', $name, $content ) );
+		// Set mail's subject and body
+		$phpmailer->Subject = $subject;
+
+		if ( is_string( $message ) ) {
+			$phpmailer->Body = $message;
+
+			// Set Content-Type
+			// If we don't have a content-type from the input headers
+			if ( ! isset( $content_type ) ) {
+				$content_type = 'text/plain';
 			}
 
+			/**
+			 * Filters the wp_mail() content type.
+			 *
+			 * @since 2.3.0
+			 *
+			 * @param string $content_type Default wp_mail() content type.
+			 */
+			$content_type = apply_filters( 'wp_mail_content_type', $content_type );
+
+			$phpmailer->ContentType = $content_type;
+
+			// Set whether it's plaintext, depending on $content_type
+			if ( 'text/html' === $content_type ) {
+				$phpmailer->isHTML( true );
+			}
+
+			// For backwards compatibility, new multipart emails should use
+			// the array style $message. This never really worked well anyway
 			if ( false !== stripos( $content_type, 'multipart' ) && ! empty( $boundary ) ) {
 				$phpmailer->addCustomHeader( sprintf( "Content-Type: %s;\n\t boundary=\"%s\"", $content_type, $boundary ) );
 			}
+		} elseif ( is_array( $message ) ) {
+			foreach ( $message as $type => $bodies ) {
+				foreach ( (array) $bodies as $body ) {
+					if ( 'text/html' === $type ) {
+						$phpmailer->Body = $body;
+					} elseif ( 'text/plain' === $type ) {
+						$phpmailer->AltBody = $body;
+					} else {
+						$phpmailer->addAttachment( $body, '', 'base64', $type );
+					}
+				}
+			}
+		}
+
+		// Set to use PHP's mail()
+		$phpmailer->isMail();
+
+		// Set custom headers
+		if ( ! empty( $headers ) ) {
+			foreach ( (array) $headers as $name => $content ) {
+				$phpmailer->addCustomHeader( sprintf( '%1$s: %2$s', $name, $content ) );
+			}
 		}
 
 		if ( ! empty( $attachments ) ) {
diff --git a/tests/phpunit/tests/mail.php b/tests/phpunit/tests/mail.php
index 951615136b..ad0323e6ae 100644
--- a/tests/phpunit/tests/mail.php
+++ b/tests/phpunit/tests/mail.php
@@ -85,6 +85,71 @@ class Tests_Mail extends WP_UnitTestCase {
 		$this->assertTrue( strpos( $mailer->get_sent()->header, 'charset=' ) > 0 );
 	}
 
+	/**
+	 * @ticket 15448
+	 */
+	function test_wp_mail_plain_and_html() {
+		$to = 'user@example.com';
+		$subject = 'Test email with plain text and html versions';
+		$messages = array( 'text/plain' => 'Here is some plain text.',
+					   'text/html' =>'<html><head></head><body>Here is the HTML with UTF-8 γειά σου Κόσμε;-)<body></html>' );
+
+		wp_mail( $to, $subject, $messages );
+
+		preg_match( '/boundary="(.*)"/', $GLOBALS['phpmailer']->mock_sent[0]['header'], $matches );
+		$boundry = $matches[1];
+		$body = 'This is a multi-part message in MIME format.
+
+--' . $boundry . '
+Content-Type: text/plain; charset=us-ascii
+
+Here is some plain text.
+
+
+--' . $boundry . '
+Content-Type: text/html; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+<html><head></head><body>Here is the HTML with UTF-8 γειά σου Κόσμε;-)<body></html>
+
+
+
+--' . $boundry . '--
+';
+		// We need some better assertions here but these test the behaviour for now.
+		$this->assertEquals( $body, $GLOBALS['phpmailer']->mock_sent[0]['body'] );
+		$this->assertSame( 1, substr_count( $GLOBALS['phpmailer']->mock_sent[0]['header'], 'Content-Type: multipart/alternative;' ) );
+		$this->assertSame( 1, substr_count( $GLOBALS['phpmailer']->mock_sent[0]['header'], 'Content-Type:' ) );
+	}
+
+	/*
+	 * 'phpmailer_init' action for test_wp_mail_plain_and_html_workaround().
+	 */
+	function wp_mail_set_alt_body( $mailer ) {
+		$mailer->AltBody = strip_tags( $mailer->Body );
+	}
+
+	/**
+	 * @ticket 15448
+	 *
+	 * Check workarounds using phpmailer_init still work around.
+	 */
+	function test_wp_mail_plain_and_html_workaround() {
+		$to = 'user@example.com';
+		$subject = 'Test email with plain text derived from html version';
+		$message = '<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /></head><body><p>Hello World! γειά σου Κόσμε</p></body></html>';
+
+		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' ) );
+
+		$this->assertSame( 1, substr_count( $GLOBALS['phpmailer']->mock_sent[0]['header'], 'Content-Type: multipart/alternative;' ) );
+		$this->assertSame( 1, substr_count( $GLOBALS['phpmailer']->mock_sent[0]['header'], 'Content-Type:' ) );
+		$this->assertSame( 1, substr_count( $GLOBALS['phpmailer']->mock_sent[0]['body'], 'Content-Type: text/plain; charset=UTF-8' ) );
+		$this->assertSame( 1, substr_count( $GLOBALS['phpmailer']->mock_sent[0]['body'], 'Content-Type: text/html; charset=UTF-8' ) );
+		$this->assertSame( 2, substr_count( $GLOBALS['phpmailer']->mock_sent[0]['body'], 'Content-Type:' ) );
+	}
+
 	/**
 	 * @ticket 17305
 	 */
