diff --git a/CRM/Utils/Mail.php b/CRM/Utils/Mail.php index 0583274823cf..bee812ff4911 100644 --- a/CRM/Utils/Mail.php +++ b/CRM/Utils/Mail.php @@ -562,8 +562,29 @@ public static function setMimeParams($message, $params = NULL) { * @return null|string */ public static function formatRFC822Email($name, $email, $useQuote = FALSE) { - $result = NULL; + if (empty($email)) { + return NULL; + } + + // Already formatted + if (str_contains($email, '<')) { + return $email; + } + + // Split multiple emails + if (str_contains($email, ',') || str_contains($email, ';')) { + $emails = preg_split('/[,;]+/', $email); + $formatted = []; + foreach ($emails as $singleEmail) { + $singleEmail = trim($singleEmail); + if ($singleEmail !== '') { + $formatted[] = self::formatRFC822Email($name, $singleEmail, $useQuote); + } + } + return implode(', ', $formatted); + } + $email = trim($email); $name = trim($name ?? ''); // strip out double quotes if present at the beginning AND end @@ -587,11 +608,10 @@ public static function formatRFC822Email($name, $email, $useQuote = FALSE) { $name = '"' . $name . '"'; } - $result = "$name "; + return "$name <{$email}>"; } - $result .= "<{$email}>"; - return $result; + return "<{$email}>"; } /** diff --git a/tests/phpunit/CRM/Utils/MailTest.php b/tests/phpunit/CRM/Utils/MailTest.php index b195bf28fb9d..fd33fc3ec572 100644 --- a/tests/phpunit/CRM/Utils/MailTest.php +++ b/tests/phpunit/CRM/Utils/MailTest.php @@ -50,16 +50,52 @@ public function testFormatRFC822(): void { 'result' => '"User, Test" ', 'useQuote' => TRUE, ], + [ + 'name' => '', + 'email' => 'foo@bar.com', + 'result' => '', + ], + [ + 'name' => NULL, + 'email' => 'foo@bar.com', + 'result' => '', + ], + [ + 'name' => '', + 'email' => 'foo@bar.com, baz@bar.com', + 'result' => ', ', + ], + [ + 'name' => NULL, + 'email' => 'foo@bar.com, baz@bar.com', + 'result' => ', ', + ], + [ + 'name' => '', + 'email' => 'foo@bar.com; baz@bar.com', + 'result' => ', ', + ], ]; foreach ($values as $value) { $result = CRM_Utils_Mail::formatRFC822Email($value['name'], $value['email'], $value['useQuote'] ?? FALSE ); - $this->assertEquals($result, $value['result'], 'Expected encoding does not match'); + $this->assertEquals($value['result'], $result, 'Expected encoding does not match'); } } + public function testSetEmailHeadersMultipleRecipients(): void { + $params = [ + 'toEmail' => 'foo@bar.com, baz@bar.com', + 'from' => 'admin@example.com', + 'subject' => 'Test', + 'text' => 'Hello', + ]; + [$headers, $message] = CRM_Utils_Mail::setEmailHeaders($params); + $this->assertEquals(', ', $headers['To']); + } + /** * Test exception handling in mail function. */ diff --git a/tests/phpunit/api/v3/JobTest.php b/tests/phpunit/api/v3/JobTest.php index 923e571ffc7c..5e1f80a6056e 100644 --- a/tests/phpunit/api/v3/JobTest.php +++ b/tests/phpunit/api/v3/JobTest.php @@ -2471,6 +2471,39 @@ public function testMailReportForCsv(): void { $mut->stop(); } + /** + * Test that the mail_report job sends an email when multiple recipients are specified in email_to. + */ + public function testMailReportMultipleRecipients(): void { + $mut = new CiviMailUtils($this, TRUE); + $reportInstance = $this->createReportInstance(); + $this->callAPISuccess('ReportInstance', 'create', [ + 'id' => $reportInstance['id'], + 'email_to' => 'person1@example.com, person2@example.com', + ]); + + if (empty($_SERVER['QUERY_STRING'])) { + $_SERVER['QUERY_STRING'] = 'reset=1'; + } + + ob_start(); + $this->callApiV3Success('Job', 'mail_report', [ + 'instanceId' => $reportInstance['id'], + 'format' => 'pdf', + ]); + ob_end_clean(); + + $message = $mut->getMostRecentEmail('ezc'); + + $this->assertEquals('This is the email subject', $message->subject); + $this->assertCount(2, $message->to); + $this->assertEquals('person1@example.com', $message->to[0]->email); + $this->assertEquals('person2@example.com', $message->to[1]->email); + + $mut->clearMessages(); + $mut->stop(); + } + /** * Helper to create a report instance of the contact summary report. *