From ac1d2cf38f3e23205b2b3ed67f00019a1d0c4811 Mon Sep 17 00:00:00 2001 From: Philipp Date: Sat, 19 Sep 2020 20:14:55 +0200 Subject: [PATCH 1/2] Transform email header string to header array & replace it at various situations. --- include/enotify.php | 15 ++++--- src/Object/EMail/IEmail.php | 11 ++++- src/Object/Email.php | 27 ++++++++++-- src/Util/EMailer/MailBuilder.php | 42 +++++++++++++------ src/Util/Emailer.php | 2 +- tests/src/Util/Emailer/MailBuilderTest.php | 2 +- .../Util/Emailer/SystemMailBuilderTest.php | 4 +- 7 files changed, 75 insertions(+), 28 deletions(-) diff --git a/include/enotify.php b/include/enotify.php index 8b98f90590..478b034e5f 100644 --- a/include/enotify.php +++ b/include/enotify.php @@ -87,12 +87,15 @@ function notification($params) } $nickname = $user["nickname"]; + // Creates a new email builder for the notification email + $emailBuilder = DI::emailer()->newNotifyMail(); + // with $params['show_in_notification_page'] == false, the notification isn't inserted into // the database, and an email is sent if applicable. // default, if not specified: true $show_in_notification_page = isset($params['show_in_notification_page']) ? $params['show_in_notification_page'] : true; - $additional_mail_header = "X-Friendica-Account: <".$nickname."@".$hostname.">\n"; + $emailBuilder->setHeader('X-Friendica-Account', '<' . $nickname . '@' . $hostname . '>'); if (array_key_exists('item', $params)) { $title = $params['item']['title']; @@ -521,13 +524,14 @@ function notification($params) 'receiver-uid' => $params['uid'], 'parent-item' => 0]; DBA::insert('notify-threads', $fields); - $additional_mail_header .= "Message-ID: " . $message_id . "\n"; + $emailBuilder->setHeader('Message-ID', $message_id); $log_msg = "include/enotify: No previous notification found for this parent:\n" . " parent: ${params['parent']}\n" . " uid : ${params['uid']}\n"; Logger::log($log_msg, Logger::DEBUG); } else { // If not, just "follow" the thread. - $additional_mail_header .= "References: " . $message_id . "\nIn-Reply-To: " . $message_id . "\n"; + $emailBuilder->setHeader('References', $message_id); + $emailBuilder->setHeader('In-Reply-To', $message_id); Logger::log("There's already a notification for this parent.", Logger::DEBUG); } } @@ -546,7 +550,6 @@ function notification($params) 'title' => $title, 'body' => $body, 'subject' => $subject, - 'headers' => $additional_mail_header, ]; Hook::callAll('enotify_mail', $datarray); @@ -565,13 +568,13 @@ function notification($params) // If a photo is present, add it to the email if (!empty($datarray['source_photo'])) { - $builder->withPhoto( + $emailBuilder->withPhoto( $datarray['source_photo'], $datarray['source_link'] ?? $sitelink, $datarray['source_name'] ?? $sitename); } - $email = $builder->build(); + $email = $emailBuilder->build(); // use the Emailer class to send the message return DI::emailer()->send($email); diff --git a/src/Object/EMail/IEmail.php b/src/Object/EMail/IEmail.php index 77b5901f37..31384c395c 100644 --- a/src/Object/EMail/IEmail.php +++ b/src/Object/EMail/IEmail.php @@ -83,11 +83,18 @@ interface IEmail extends JsonSerializable function getMessage(bool $plain = false); /** - * Gets any additional mail header + * Gets the additional mail header array + * + * @return string[][] + */ + function getAdditionalMailHeader(); + + /** + * Gets the additional mail header as string - EOL separated * * @return string */ - function getAdditionalMailHeader(); + function getAdditionalMailHeaderString(); /** * Returns the current email with a new recipient diff --git a/src/Object/Email.php b/src/Object/Email.php index 96a7ad88cb..9f78763127 100644 --- a/src/Object/Email.php +++ b/src/Object/Email.php @@ -47,14 +47,14 @@ class Email implements IEmail /** @var string */ private $msgText; - /** @var string */ - private $additionalMailHeader = ''; + /** @var string[][] */ + private $additionalMailHeader; /** @var int|null */ - private $toUid = null; + private $toUid; public function __construct(string $fromName, string $fromAddress, string $replyTo, string $toAddress, string $subject, string $msgHtml, string $msgText, - string $additionalMailHeader = '', int $toUid = null) + array $additionalMailHeader = [], int $toUid = null) { $this->fromName = $fromName; $this->fromAddress = $fromAddress; @@ -127,6 +127,25 @@ class Email implements IEmail return $this->additionalMailHeader; } + /** + * {@inheritDoc} + */ + public function getAdditionalMailHeaderString() + { + $headerString = ''; + + foreach ($this->additionalMailHeader as $name => $values) { + if (is_array($values)) { + foreach ($values as $value) { + $headerString .= $name . ': ' . $value . '\n'; + } + } else { + $headerString .= $name . ': ' . $values . '\n'; + } + } + return $headerString; + } + /** * {@inheritDoc} */ diff --git a/src/Util/EMailer/MailBuilder.php b/src/Util/EMailer/MailBuilder.php index 7bdb978c81..6a7412f683 100644 --- a/src/Util/EMailer/MailBuilder.php +++ b/src/Util/EMailer/MailBuilder.php @@ -49,7 +49,7 @@ abstract class MailBuilder /** @var LoggerInterface */ protected $logger; - /** @var string */ + /** @var string[][] */ protected $headers; /** @var string */ @@ -76,13 +76,14 @@ abstract class MailBuilder $hostname = substr($hostname, 0, strpos($hostname, ':')); } - $this->headers = ""; - $this->headers .= "Precedence: list\n"; - $this->headers .= "X-Friendica-Host: " . $hostname . "\n"; - $this->headers .= "X-Friendica-Platform: " . FRIENDICA_PLATFORM . "\n"; - $this->headers .= "X-Friendica-Version: " . FRIENDICA_VERSION . "\n"; - $this->headers .= "List-ID: \n"; - $this->headers .= "List-Archive: <" . $baseUrl->get() . "/notifications/system>\n"; + $this->headers = [ + 'Precedence' => ['list'], + 'X-Friendica-Host' => [$hostname], + 'X-Friendica-Platform' => [FRIENDICA_PLATFORM], + 'X-Friendica-Version' => [FRIENDICA_VERSION], + 'List-ID' => [''], + 'List-Archive' => ['<' . $baseUrl->get() . '/notifications/system>'], + ]; } /** @@ -159,15 +160,32 @@ abstract class MailBuilder } /** - * Adds new headers to the default headers + * Adds a value to a header * - * @param string $headers New headers + * @param string $name The header name + * @param string $value The value of the header to add * * @return static */ - public function addHeaders(string $headers) + public function addHeader(string $name, string $value) { - $this->headers .= $headers; + $this->headers[$name][] = $value; + + return $this; + } + + /** + * Sets a value to a header (overwrites existing values) + * + * @param string $name The header name + * @param string $value The value to set + * + * @return static + */ + public function setHeader(string $name, string $value) + { + $this->headers[$name] = []; + $this->headers[$name][] = $value; return $this; } diff --git a/src/Util/Emailer.php b/src/Util/Emailer.php index 717366248f..0594937ec8 100644 --- a/src/Util/Emailer.php +++ b/src/Util/Emailer.php @@ -151,7 +151,7 @@ class Emailer . rand(10000, 99999); // generate a multipart/alternative message header - $messageHeader = $email->getAdditionalMailHeader() . + $messageHeader = $email->getAdditionalMailHeaderString() . "From: $fromName <{$fromAddress}>\n" . "Reply-To: $fromName <{$replyTo}>\n" . "MIME-Version: 1.0\n" . diff --git a/tests/src/Util/Emailer/MailBuilderTest.php b/tests/src/Util/Emailer/MailBuilderTest.php index 4bae9bfd8f..202ad587b6 100644 --- a/tests/src/Util/Emailer/MailBuilderTest.php +++ b/tests/src/Util/Emailer/MailBuilderTest.php @@ -61,7 +61,7 @@ class MailBuilderTest extends MockedTest $this->baseUrl->shouldReceive('getHostname')->andReturn('friendica.local'); $this->baseUrl->shouldReceive('get')->andReturn('http://friendica.local'); - $this->defaultHeaders = ""; + $this->defaultHeaders = []; } public function assertEmail(IEmail $email, array $asserts) diff --git a/tests/src/Util/Emailer/SystemMailBuilderTest.php b/tests/src/Util/Emailer/SystemMailBuilderTest.php index 45466bb8ae..6991ce8d44 100644 --- a/tests/src/Util/Emailer/SystemMailBuilderTest.php +++ b/tests/src/Util/Emailer/SystemMailBuilderTest.php @@ -41,7 +41,7 @@ class SystemMailBuilderTest extends MockedTest /** @var BaseURL */ private $baseUrl; - /** @var string */ + /** @var string[] */ private $defaultHeaders; public function setUp() @@ -60,7 +60,7 @@ class SystemMailBuilderTest extends MockedTest $this->baseUrl->shouldReceive('getHostname')->andReturn('friendica.local'); $this->baseUrl->shouldReceive('get')->andReturn('http://friendica.local'); - $this->defaultHeaders = ""; + $this->defaultHeaders = []; } /** From c41614fef1c42c200a3fc0e07eb5bfac95e066ae Mon Sep 17 00:00:00 2001 From: Philipp Date: Sat, 19 Sep 2020 22:49:44 +0200 Subject: [PATCH 2/2] Add improvements --- src/Util/EMailer/MailBuilder.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Util/EMailer/MailBuilder.php b/src/Util/EMailer/MailBuilder.php index 6a7412f683..24190fe4d4 100644 --- a/src/Util/EMailer/MailBuilder.php +++ b/src/Util/EMailer/MailBuilder.php @@ -184,8 +184,7 @@ abstract class MailBuilder */ public function setHeader(string $name, string $value) { - $this->headers[$name] = []; - $this->headers[$name][] = $value; + $this->headers[$name] = [$value]; return $this; }