diff --git a/inmail_collect/src/Plugin/collect/Model/InmailMessage.php b/inmail_collect/src/Plugin/collect/Model/InmailMessage.php index 9c2f6e6..09e5956 100644 --- a/inmail_collect/src/Plugin/collect/Model/InmailMessage.php +++ b/inmail_collect/src/Plugin/collect/Model/InmailMessage.php @@ -86,6 +86,7 @@ class InmailMessage extends ModelPluginBase implements ContainerFactoryPluginInt /** @var \Drupal\inmail\MIME\MessageInterface $parsed_data */ $parsed_data = $data->getParsedData(); $output = parent::buildTeaser($data); + $to_addresses = $parsed_data->getTo(); $output['subject'] = array( '#type' => 'item', @@ -100,7 +101,7 @@ class InmailMessage extends ModelPluginBase implements ContainerFactoryPluginInt $output['to'] = array( '#type' => 'item', '#title' => $this->t('To'), - '#markup' => htmlentities($parsed_data->getTo()), + '#markup' => htmlentities(reset($to_addresses)), ); return $output; diff --git a/inmail_collect/src/Plugin/inmail/Handler/CollectHandler.php b/inmail_collect/src/Plugin/inmail/Handler/CollectHandler.php index e458318..3021bd5 100644 --- a/inmail_collect/src/Plugin/inmail/Handler/CollectHandler.php +++ b/inmail_collect/src/Plugin/inmail/Handler/CollectHandler.php @@ -47,7 +47,8 @@ class CollectHandler extends HandlerBase { public function invoke(MessageInterface $message, ProcessorResultInterface $processor_result) { // For successful processing, a message needs to follow the standards. // Some aspects are critical. Check them and cancel otherwise and log. - if (!$message->getReceivedDate() || !$message->getFrom() || !$message->getTo() || $message->getSubject() === NULL) { + $to_addresses = $message->getTo(); + if (!$message->getReceivedDate() || !$message->getFrom() || !reset($to_addresses) || $message->getSubject() === NULL) { \Drupal::logger('inmail')->info('Not creating container from message missing necessary header fields.'); return; } @@ -78,7 +79,7 @@ class CollectHandler extends HandlerBase { $data = array( // Note the Subject field is optional by RFC882. 'header-subject' => $message->getSubject(), - 'header-to' => $message->getTo(), + 'header-to' => current($to_addresses), 'header-from' => $message->getFrom(), 'header-message-id' => $message->getMessageId(), 'deliverer' => $processor_result->getDeliverer()->id(), diff --git a/src/MIME/MessageInterface.php b/src/MIME/MessageInterface.php index b3573d5..8be72da 100644 --- a/src/MIME/MessageInterface.php +++ b/src/MIME/MessageInterface.php @@ -37,9 +37,8 @@ interface MessageInterface extends EntityInterface { * @param bool $decode * Optional value to indicate if header is in punycode form. * - * @return string|null - * The content of the 'To' header field, or null if that field does not - * exist. + * @return array + * List of recipient addresses. */ public function getTo($decode = FALSE); @@ -56,6 +55,17 @@ interface MessageInterface extends EntityInterface { public function getFrom($decode = FALSE); /** + * Returns the addresses of other recipients. + * + * @param bool $decode + * Optional value to indicate if header is in punycode form. + * + * @return array + * The list of other recipients. + */ + public function getCC($decode = FALSE); + + /** * Returns the date when the message was received by the recipient. * * @return \Drupal\Component\DateTime\DateTimePlus diff --git a/src/MIME/MessageTrait.php b/src/MIME/MessageTrait.php index ca921a0..2848f36 100644 --- a/src/MIME/MessageTrait.php +++ b/src/MIME/MessageTrait.php @@ -11,29 +11,14 @@ trait MessageTrait { * {@inheritdoc} */ public function getTo($decode = FALSE) { - $body = $this->getHeader()->getFieldBody('To'); - if ($decode) { - if (strpos($body, '@') !== FALSE) { - // Extracting body after '@' sign for proper IDN decoding. - $body = explode('@', $body, 2)[0] . '@' . idn_to_utf8(explode('@', $body, 2)[1]); - } - //@todo Properly parse Mail Address https://www.drupal.org/node/2800585 - } - return $body; + return $this->getHeaderFieldBody('To', $decode); } /** * {@inheritdoc} */ public function getFrom($decode = FALSE) { - $body = $this->getHeader()->getFieldBody('From'); - if ($decode) { - if (strpos($body, '@') !== FALSE) { - $body = explode('@', $body, 2)[0] . '@' . idn_to_utf8(explode('@', $body, 2)[1]); - } - //@todo Properly parse Mail Address https://www.drupal.org/node/2800585 - } - return $body; + return $this->getHeaderFieldBody('From', $decode); } /** @@ -46,4 +31,37 @@ trait MessageTrait { */ abstract public function getHeader(); + /** + * {@inheritdoc} + */ + public function getCC($decode = FALSE) { + return $this->getHeaderFieldBody('Cc', $decode); + } + + /** + * Helper method to extract field body. + * + * @param string $field + * Name of field to extract. + * + * @param bool $decode + * Optional value to indicate if header is in punycode form. + * + * @return string|null + * The content of the header field, or null if that field does not + * exist. + */ + protected function getHeaderFieldBody($field, $decode = FALSE) { + $body = $this->getHeader()->getFieldBody($field); + if ($decode) { + if (strpos($body, '@') !== FALSE) { + // Extracting body after '@' sign for proper IDN decoding. + $body = explode('@', $body, 2)[0] . '@' . idn_to_utf8(explode('@', $body, 2)[1]); + } + //@todo Properly parse Mail Address https://www.drupal.org/node/2800585 + } + // By RFC 2822, To and Cc header fields can occur multiple times. + return ($field == 'Cc' || $field == 'To') ? [$body] : $body; + } + } diff --git a/src/Plugin/inmail/Analyzer/VERPAnalyzer.php b/src/Plugin/inmail/Analyzer/VERPAnalyzer.php index bca8cac..9b6cd28 100644 --- a/src/Plugin/inmail/Analyzer/VERPAnalyzer.php +++ b/src/Plugin/inmail/Analyzer/VERPAnalyzer.php @@ -63,7 +63,8 @@ class VerpAnalyzer extends AnalyzerBase { // Match the modified Return-Path (returnpath+alice=example.com@website.com) // and put the parts of the recipient address (alice, example.com) in // $matches. - if (preg_match(':^' . $return_path_split[0] . '\+(.*)=(.*)@' . $return_path_split[1] . '$:', $message->getTo(), $matches)) { + $to_addresses = $message->getTo(); + if (preg_match(':^' . $return_path_split[0] . '\+(.*)=(.*)@' . $return_path_split[1] . '$:', reset($to_addresses), $matches)) { // Report the recipient address (alice@example.com). $bounce_data->setRecipient($matches[1] . '@' . $matches[2]); } diff --git a/src/Tests/IntegrationTest.php b/src/Tests/IntegrationTest.php index 1c4569e..6d950bf 100644 --- a/src/Tests/IntegrationTest.php +++ b/src/Tests/IntegrationTest.php @@ -72,6 +72,7 @@ class IntegrationTest extends WebTestBase { /** @var \Drupal\inmail\MIME\Parser $parser */ $parser = \Drupal::service('inmail.mime_parser'); $message = $parser->parseMessage($raw_multipart); + $to_addresses = $message->getTo(); // Test "teaser" view mode of Inmail message element. $this->drupalGet('admin/inmail-test/email/' . $event->id() . '/teaser'); @@ -84,7 +85,7 @@ class IntegrationTest extends WebTestBase { $this->assertText('Email display'); $this->assertText('Received: ' . $message->getReceivedDate()); $this->assertText('From: ' . htmlspecialchars($message->getFrom())); - $this->assertText('To: ' . htmlspecialchars($message->getTo())); + $this->assertText('To: ' . htmlspecialchars(reset($to_addresses))); // Assert message parts. $this->assertText('plain'); $this->assertText('html'); diff --git a/templates/inmail-message.html.twig b/templates/inmail-message.html.twig index 3c56e25..08dfc9a 100644 --- a/templates/inmail-message.html.twig +++ b/templates/inmail-message.html.twig @@ -32,7 +32,7 @@

Received: {{ message.getReceivedDate() }}

From: {{ message.from }}

-

To: {{ message.to }}

+

To: {{ message.to | first }}

Subject: {{ message.subject }}

{# Use getPlainText() after https://www.drupal.org/node/2405069. #}

Body: {{ message.getDecodedBody() }}

diff --git a/templates/inmail-multipart-message.html.twig b/templates/inmail-multipart-message.html.twig index 580452b..19d20d7 100644 --- a/templates/inmail-multipart-message.html.twig +++ b/templates/inmail-multipart-message.html.twig @@ -32,7 +32,7 @@

Received: {{ message.getReceivedDate() }}

From: {{ message.from }}

-

To: {{ message.to }}

+

To: {{ message.to | first }}

Subject: {{ message.subject }}

{% endif %} diff --git a/tests/src/Unit/MIME/MessageTest.php b/tests/src/Unit/MIME/MessageTest.php index 4d9afcf..bd123be 100644 --- a/tests/src/Unit/MIME/MessageTest.php +++ b/tests/src/Unit/MIME/MessageTest.php @@ -44,9 +44,11 @@ class MessageTest extends UnitTestCase { */ public function testGetTo() { $message = new Message(new Header([['name' => 'To', 'body' => 'Foo']]), 'Bar'); - $this->assertEquals('Foo', $message->getTo()); + $to_field = $message->getTo(); + $this->assertEquals('Foo', reset($to_field)); $message = new Message(new Header([['name' => 'To', 'body' => 'helloWorld@xn--xample-9ua.com']]), 'Bar'); - $this->assertEquals('helloWorld@éxample.com', $message->getTo(TRUE)); + $to_field = $message->getTo(TRUE); + $this->assertEquals('helloWorld@éxample.com', reset($to_field)); } /** @@ -77,6 +79,17 @@ class MessageTest extends UnitTestCase { } /** + * Tests the other recipients getter. + * + * @covers ::getCC + */ + public function testGetCC() { + $message = new Message(new Header([['name' => 'Cc', 'body' => 'sun_is_shinning@example.com']]), 'I am a body'); + $cc_field = $message->getCC(); + $this->assertEquals('sun_is_shinning@example.com', reset($cc_field)); + } + + /** * Tests the message is valid and contains necessary fields. */ public function testValidation() {