Unverified Commit ab49a62b authored by larowlan's avatar larowlan
Browse files

Issue #84883 by quietone, alexpott, DuaelFr, scor, roderik, TR, pillarsdotnet,...

Issue #84883 by quietone, alexpott, DuaelFr, scor, roderik, TR, pillarsdotnet, jungle, ayushmishra206, greggles, dww, ximo, Hardik_Patel_12, netbjarne, kiamlaluno, longwave, earnie: Unicode::mimeHeaderEncode() doesn't correctly follow RFC 2047
parent 89fcf77b
......@@ -2,6 +2,8 @@
namespace Drupal\Component\Utility;
@trigger_error('\Drupal\Component\Utility\Mail is deprecated in drupal:9.2.0 and is removed from drupal:10.0.0. See https://www.drupal.org/node/3207439', E_USER_DEPRECATED);
/**
* Provides helpers to ensure emails are compliant with RFCs.
*
......@@ -29,8 +31,15 @@ class Mail {
* @return string
* A RFC compliant version of the string, ready to be used as
* "display-name" in mail originator header fields.
*
* @deprecated in drupal:9.2.0 and is removed from drupal:10.0.0. Use
* \Symfony\Component\Mime\Header\MailboxHeader instead.
*
* @see https://www.drupal.org/node/3207439
*/
public static function formatDisplayName($string) {
@trigger_error('\Drupal\Component\Utility\Mail::formatDisplayName() is deprecated in drupal:9.2.0 and is removed from drupal:10.0.0. Use \Symfony\Component\Mime\Header\MailboxHeader instead. See https://www.drupal.org/node/3207439', E_USER_DEPRECATED);
// Make sure we don't process html-encoded characters. They may create
// unneeded trouble if left encoded, besides they will be correctly
// processed if decoded.
......
......@@ -393,8 +393,14 @@ public static function strcasecmp($str1, $str2) {
*
* @return string
* The mime-encoded header.
*
* @deprecated in drupal:9.2.0 and is removed from drupal:10.0.0. Use
* \Symfony\Component\Mime\Header\UnstructuredHeader instead.
*
* @see https://www.drupal.org/node/3207439
*/
public static function mimeHeaderEncode($string, $shorten = FALSE) {
@trigger_error('\Drupal\Component\Utility\Unicode::mimeHeaderEncode() is deprecated in drupal:9.2.0 and is removed from drupal:10.0.0. Use \Symfony\Component\Mime\Header\UnstructuredHeader instead. See https://www.drupal.org/node/3207439', E_USER_DEPRECATED);
if (preg_match('/[^\x20-\x7E]/', $string)) {
// floor((75 - strlen("=?UTF-8?B??=")) * 0.75);
$chunk_size = 47;
......@@ -423,8 +429,14 @@ public static function mimeHeaderEncode($string, $shorten = FALSE) {
*
* @return string
* The mime-decoded header.
*
* @deprecated in drupal:9.2.0 and is removed from drupal:10.0.0. Use
* iconv_mime_decode() instead.
*
* @see https://www.drupal.org/node/3207439
*/
public static function mimeHeaderDecode($header) {
@trigger_error('\Drupal\Component\Utility\Unicode::mimeHeaderDecode() is deprecated in drupal:9.2.0 and is removed from drupal:10.0.0. Use iconv_mime_decode() instead. See https://www.drupal.org/node/3207439', E_USER_DEPRECATED);
$callback = function ($matches) {
$data = (strtolower($matches[2]) == 'b') ? base64_decode($matches[3]) : str_replace('_', ' ', quoted_printable_decode($matches[3]));
if (strtolower($matches[1]) != 'utf-8') {
......
......@@ -5,7 +5,6 @@
use Drupal\Component\Render\MarkupInterface;
use Drupal\Component\Render\PlainTextOutput;
use Drupal\Component\Utility\Html;
use Drupal\Component\Utility\Mail as MailHelper;
use Drupal\Core\Logger\LoggerChannelFactoryInterface;
use Drupal\Core\Messenger\MessengerTrait;
use Drupal\Core\Plugin\DefaultPluginManager;
......@@ -17,6 +16,8 @@
use Drupal\Core\Render\RendererInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\StringTranslation\TranslationInterface;
use Symfony\Component\Mime\Address;
use Symfony\Component\Mime\Header\MailboxHeader;
/**
* Provides a Mail plugin manager.
......@@ -255,9 +256,12 @@ public function doMail($module, $key, $to, $langcode, $params = [], $reply = NUL
// To prevent email from looking like spam, the addresses in the Sender and
// Return-Path headers should have a domain authorized to use the
// originating SMTP server.
$headers['Sender'] = $headers['Return-Path'] = $site_mail;
$headers['From'] = $headers['Sender'] = $headers['Return-Path'] = $site_mail;
// Make sure the site-name is a RFC-2822 compliant 'display-name'.
$headers['From'] = MailHelper::formatDisplayName($site_config->get('name')) . ' <' . $site_mail . '>';
if ($site_mail) {
$mailbox = new MailboxHeader('From', new Address($site_mail, $site_config->get('name') ?: ''));
$headers['From'] = $mailbox->getBodyAsString();
}
if ($reply) {
$headers['Reply-to'] = $reply;
}
......
......@@ -2,10 +2,11 @@
namespace Drupal\Core\Mail\Plugin\Mail;
use Drupal\Component\Utility\Unicode;
use Drupal\Core\Mail\MailFormatHelper;
use Drupal\Core\Mail\MailInterface;
use Drupal\Core\Site\Settings;
use Symfony\Component\Mime\Header\Headers;
use Symfony\Component\Mime\Header\UnstructuredHeader;
/**
* Defines the default Drupal mail backend, using PHP's native mail() function.
......@@ -18,6 +19,13 @@
*/
class PhpMail implements MailInterface {
/**
* A list of headers that can contain multiple email addresses.
*
* @see \Symfony\Component\Mime\Header\Headers::HEADER_CLASS_MAP
*/
private const MAILBOX_LIST_HEADERS = ['from', 'to', 'reply-to', 'cc', 'bcc'];
/**
* The configuration factory.
*
......@@ -75,13 +83,17 @@ public function mail(array $message) {
unset($message['headers']['Return-Path']);
}
}
$mimeheaders = [];
$headers = new Headers();
foreach ($message['headers'] as $name => $value) {
$mimeheaders[] = $name . ': ' . Unicode::mimeHeaderEncode($value);
if (in_array(strtolower($name), self::MAILBOX_LIST_HEADERS, TRUE)) {
$value = explode(',', $value);
}
$headers->addHeader($name, $value);
}
$line_endings = Settings::get('mail_line_endings', PHP_EOL);
// Prepare mail commands.
$mail_subject = Unicode::mimeHeaderEncode($message['subject']);
$mail_subject = (new UnstructuredHeader('subject', $message['subject']))->getBodyAsString();
// Note: email uses CRLF for line-endings. PHP's API requires LF
// on Unix and CRLF on Windows. Drupal automatically guesses the
// line-ending format appropriate for your system. If you need to
......@@ -89,7 +101,8 @@ public function mail(array $message) {
$mail_body = preg_replace('@\r?\n@', $line_endings, $message['body']);
// For headers, PHP's API suggests that we use CRLF normally,
// but some MTAs incorrectly replace LF with CRLF. See #234403.
$mail_headers = implode("\n", $mimeheaders);
$mail_headers = str_replace("\r\n", "\n", $headers->toString());
$mail_subject = str_replace("\r\n", "\n", $mail_subject);
$request = \Drupal::request();
......
......@@ -907,7 +907,6 @@ middlewares
midgardmvc
mikey
milli
mimeheaders
mimetypes
minifyzombies
minimatch
......
......@@ -3,7 +3,6 @@
namespace Drupal\Tests\system\Kernel\Mail;
use Drupal\Component\Utility\Random;
use Drupal\Component\Utility\Unicode;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Mail\MailFormatHelper;
use Drupal\Core\Mail\Plugin\Mail\TestMailCollector;
......@@ -147,9 +146,9 @@ public function testFromAndReplyToHeader() {
$captured_emails = \Drupal::state()->get('system.test_mail_collector');
$sent_message = end($captured_emails);
// From header is correctly encoded.
$this->assertEquals('=?UTF-8?B?RHLDqXBhbCB0aGlzIGlzIGEgdmVyeSBsb25nIHRlc3Qgc2VudGVuY2UgdG8gdGU=?= <mailtest@example.com>', $sent_message['headers']['From']);
$this->assertEquals('=?utf-8?Q?Dr=C3=A9pal?= this is a very long test sentence to test what happens with very long site names <mailtest@example.com>', $sent_message['headers']['From']);
// From header is correctly encoded.
$this->assertEquals('Drépal this is a very long test sentence to te <mailtest@example.com>', Unicode::mimeHeaderDecode($sent_message['headers']['From']));
$this->assertEquals('Drépal this is a very long test sentence to test what happens with very long site names <mailtest@example.com>', iconv_mime_decode($sent_message['headers']['From']));
$this->assertFalse(isset($sent_message['headers']['Reply-to']), 'Message reply-to is not set if not specified.');
// Errors-to header must not be set, it is deprecated.
$this->assertFalse(isset($sent_message['headers']['Errors-To']));
......@@ -179,9 +178,9 @@ public function testFromAndReplyToHeader() {
$captured_emails = \Drupal::state()->get('system.test_mail_collector');
$sent_message = end($captured_emails);
// From header is correctly encoded.
$this->assertEquals('=?UTF-8?B?RHLDqXBhbCwgInNpXHRlIg==?= <mailtest@example.com>', $sent_message['headers']['From']);
$this->assertEquals('=?utf-8?Q?Dr=C3=A9pal=2C_=22si=5Cte=22?= <mailtest@example.com>', $sent_message['headers']['From']);
// From header is correctly encoded.
$this->assertEquals($site_name . ' <mailtest@example.com>', Unicode::mimeHeaderDecode($sent_message['headers']['From']));
$this->assertEquals($site_name . ' <mailtest@example.com>', iconv_mime_decode($sent_message['headers']['From']));
}
/**
......
......@@ -4,15 +4,18 @@
use Drupal\Component\Utility\Mail;
use PHPUnit\Framework\TestCase;
use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait;
/**
* Test mail helpers implemented in Mail component.
*
* @group Utility
* @group legacy
*
* @coversDefaultClass \Drupal\Component\Utility\Mail
*/
class MailTest extends TestCase {
use ExpectDeprecationTrait;
/**
* Tests RFC-2822 'display-name' formatter.
......@@ -21,6 +24,7 @@ class MailTest extends TestCase {
* @covers ::formatDisplayName
*/
public function testFormatDisplayName($string, $safe_display_name) {
$this->expectDeprecation('\Drupal\Component\Utility\Unicode::mimeHeaderEncode() is deprecated in drupal:9.2.0 and is removed from drupal:10.0.0. Use \Symfony\Component\Mime\Header\UnstructuredHeader instead. See https://www.drupal.org/node/3207439');
$this->assertEquals($safe_display_name, Mail::formatDisplayName($string));
}
......
......@@ -4,6 +4,7 @@
use Drupal\Component\Utility\Unicode;
use PHPUnit\Framework\TestCase;
use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait;
/**
* Test unicode handling features implemented in Unicode component.
......@@ -13,14 +14,17 @@
* @coversDefaultClass \Drupal\Component\Utility\Unicode
*/
class UnicodeTest extends TestCase {
use ExpectDeprecationTrait;
/**
* Tests multibyte encoding.
*
* @dataProvider providerTestMimeHeader
* @covers ::mimeHeaderEncode
* @group legacy
*/
public function testMimeHeaderEncode($value, $encoded) {
$this->expectDeprecation('\Drupal\Component\Utility\Unicode::mimeHeaderEncode() is deprecated in drupal:9.2.0 and is removed from drupal:10.0.0. Use \Symfony\Component\Mime\Header\UnstructuredHeader instead. See https://www.drupal.org/node/3207439');
$this->assertEquals($encoded, Unicode::mimeHeaderEncode($value));
}
......@@ -44,8 +48,10 @@ public function providerTestMimeHeader() {
*
* @dataProvider providerTestMimeHeaderDecode
* @covers ::mimeHeaderDecode
* @group legacy
*/
public function testMimeHeaderDecode($value, $encoded) {
$this->expectDeprecation('\Drupal\Component\Utility\Unicode::mimeHeaderDecode() is deprecated in drupal:9.2.0 and is removed from drupal:10.0.0. Use iconv_mime_decode() instead. See https://www.drupal.org/node/3207439');
$this->assertEquals($value, Unicode::mimeHeaderDecode($encoded));
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment