diff --git a/src/Queue/Task/EmailTask.php b/src/Queue/Task/EmailTask.php index 900b0c95..2e4f10d6 100644 --- a/src/Queue/Task/EmailTask.php +++ b/src/Queue/Task/EmailTask.php @@ -164,7 +164,7 @@ public function run(array $data, int $jobId): void { $settings = $data['settings'] + $this->defaults; - foreach (['to', 'from', 'cc', 'bcc', 'replyTo', 'sender', 'returnPath'] as $addressMethod) { + foreach (['to', 'from', 'cc', 'bcc', 'replyTo', 'sender', 'returnPath', 'readReceipt'] as $addressMethod) { if (!array_key_exists($addressMethod, $settings)) { continue; } @@ -174,6 +174,35 @@ public function run(array $data, int $jobId): void { unset($settings[$addressMethod]); } + // Message body keys from a serialized Message payload use different names than + // their setter methods. Route them explicitly so the generic loop does not try + // to call nonexistent `setHtmlMessage`/`setTextMessage` on the Mailer. + if (array_key_exists('htmlMessage', $settings)) { + $this->mailer->getMessage()->setBodyHtml((string)$settings['htmlMessage']); + unset($settings['htmlMessage']); + } + if (array_key_exists('textMessage', $settings)) { + $this->mailer->getMessage()->setBodyText((string)$settings['textMessage']); + unset($settings['textMessage']); + } + + // `headers` must be passed as a single positional argument — the map's string + // keys would otherwise be interpreted as named parameters under PHP 8. + if (array_key_exists('headers', $settings)) { + $this->mailer->getMessage()->setHeaders((array)$settings['headers']); + unset($settings['headers']); + } + + // `appCharset` has no setter on Mailer or Message. Fall back to the Message + // charset when a dedicated `charset` value was not also provided. + if (array_key_exists('appCharset', $settings)) { + $appCharset = (string)$settings['appCharset']; + unset($settings['appCharset']); + if (!array_key_exists('charset', $settings)) { + $this->mailer->getMessage()->setCharset($appCharset); + } + } + foreach ($settings as $method => $setting) { $setter = 'set' . ucfirst($method); if (in_array($method, ['theme', 'template', 'layout'], true)) { diff --git a/tests/TestCase/Queue/Task/EmailTaskTest.php b/tests/TestCase/Queue/Task/EmailTaskTest.php index 4eb79b16..e6523879 100644 --- a/tests/TestCase/Queue/Task/EmailTaskTest.php +++ b/tests/TestCase/Queue/Task/EmailTaskTest.php @@ -253,6 +253,72 @@ public function testRunArrayAssociativeAddressMap() { $this->assertSame(['reply@test.de' => 'Reply Name'], $mailer->getReplyTo()); } + /** + * Settings keys coming from a JSON-round-tripped `Message::__serialize()` payload + * (e.g. `htmlMessage`, `textMessage`, `appCharset`) must not be routed to + * nonexistent `set()` methods on the Mailer. + * + * @return void + */ + public function testRunArrayMessageSerializableProperties() { + $settings = [ + 'from' => 'sender@test.de', + 'to' => 'recipient@test.de', + 'subject' => 'Message Subject', + 'domain' => 'example.com', + 'charset' => 'utf-8', + 'headerCharset' => 'utf-8', + 'appCharset' => 'UTF-8', + 'emailFormat' => 'html', + 'messageId' => true, + 'htmlMessage' => '

Hello

', + 'textMessage' => 'Hello', + ]; + + $data = [ + 'settings' => $settings, + ]; + $this->Task->run($data, 0); + + $this->assertInstanceOf(Mailer::class, $this->Task->mailer); + + $message = $this->Task->mailer->getMessage(); + $this->assertSame('Message Subject', $message->getSubject()); + $this->assertSame('example.com', $message->getDomain()); + $this->assertSame('html', $message->getEmailFormat()); + $this->assertSame('utf-8', $message->getCharset()); + $this->assertSame('utf-8', $message->getHeaderCharset()); + } + + /** + * An associative `headers` map inside `settings` must not be expanded into named + * parameters when calling `Message::setHeaders()`. + * + * @return void + */ + public function testRunArrayHeadersInSettings() { + $settings = [ + 'from' => 'sender@test.de', + 'to' => 'recipient@test.de', + 'headers' => [ + 'X-Custom' => 'queued', + 'X-Other' => 'value', + ], + ]; + + $data = [ + 'settings' => $settings, + 'content' => 'Foo Bar', + ]; + $this->Task->run($data, 0); + + $this->assertInstanceOf(Mailer::class, $this->Task->mailer); + + $headers = $this->Task->mailer->getMessage()->getHeaders(['_headers']); + $this->assertSame('queued', $headers['X-Custom']); + $this->assertSame('value', $headers['X-Other']); + } + /** * @return void */