diff --git a/core/components/sendex/docs/changelog.txt b/core/components/sendex/docs/changelog.txt index 9c5a02d..f0f27f8 100644 --- a/core/components/sendex/docs/changelog.txt +++ b/core/components/sendex/docs/changelog.txt @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [#111] Mgr row-action and menu icons no longer force `font-family: "Font Awesome 5 Free"` (Sendex does not load FA5); icons inherit the mgr icon font on MODX 2.3+/3.x or bundled FA4 on older MODX. - [#25666] Transport package built on MODX 3.x stored vehicle class as `xPDO\Transport\xPDOObjectVehicle`, which MODX 2.8.8/2.8.9 cannot load (install fails with ~30 "Could not load class" errors). Release build now runs on MODX 2.x so the manifest uses the legacy vehicle format that installs on both MODX 2.8+ and 3.x. - Queue claim columns (`claimed_at`, `attempts`, `expires_at`) are ensured on Sendex bootstrap when Phinx did not apply `#105` migration, avoiding `Unknown column sxQueue.claimed_at` on live upgrades. +- [#123] Queue send resolves From/Reply headers from the linked newsletter at delivery time, so correcting `email_from` in mgr applies to pending queue rows instead of the stale snapshot from `addQueues`. ## [2.0.0-pl] - 2026-07-25 diff --git a/core/components/sendex/model/sendex/sxnewslettermailer.class.php b/core/components/sendex/model/sendex/sxnewslettermailer.class.php index 69b4239..c25c121 100644 --- a/core/components/sendex/model/sendex/sxnewslettermailer.class.php +++ b/core/components/sendex/model/sendex/sxnewslettermailer.class.php @@ -8,7 +8,8 @@ * Post-#62 mail paths (issue originally named sxNewsletter::send/checkEmail): * - activation: snippet → Sendex::sendEmail → buildActivationMessage * - queue build: sxNewsletterQueueBuilder::addQueues → compact row (headers only) - * - queue send: sxQueueSender::deliverMail → messageFromQueue (+ sxQueueBodyRenderer when body empty) + * - queue send: sxQueueSender::deliverMail → messageFromQueue (+ sxQueueBodyRenderer when body empty). + * From/Reply headers come from the linked newsletter at send time (#123), not the queue snapshot. */ class sxNewsletterMailer { @@ -107,13 +108,22 @@ public static function messageFromQueue($queue) $body = $rendered; } + $headers = self::resolveHeaders($queue, $queue->xpdo); + $newsletterId = (int) self::readField($queue, 'newsletter_id'); + if ($newsletterId > 0) { + $newsletter = $queue->xpdo->getObject('sxNewsletter', $newsletterId); + if ($newsletter) { + $headers = self::resolveHeaders($newsletter, $queue->xpdo); + } + } + return array( 'email_to' => self::sanitizeHeader(self::readField($queue, 'email_to')), 'email_body' => $body, - 'email_from' => self::sanitizeHeader(self::readField($queue, 'email_from')), - 'email_from_name' => self::sanitizeHeader(self::readField($queue, 'email_from_name')), + 'email_from' => $headers['email_from'], + 'email_from_name' => $headers['email_from_name'], 'email_subject' => self::readField($queue, 'email_subject'), - 'email_reply' => self::sanitizeHeader(self::readField($queue, 'email_reply')), + 'email_reply' => $headers['email_reply'], ); } diff --git a/tests/Unit/NewsletterMailerTest.php b/tests/Unit/NewsletterMailerTest.php index 9e9d402..b83dfeb 100644 --- a/tests/Unit/NewsletterMailerTest.php +++ b/tests/Unit/NewsletterMailerTest.php @@ -178,6 +178,36 @@ public function testMessageFromQueueSanitizesHeaderFields() $this->assertSame('reply@example.com Bcc:bad@example.com', $message['email_reply']); } + public function testMessageFromQueueUsesNewsletterHeadersWhenLinked() + { + $newsletter = new TestableNewsletter($this->modx); + $newsletter->set('id', 10); + $newsletter->set('email_from', 'fixed@example.com'); + $newsletter->set('email_from_name', 'Fixed Sender'); + $newsletter->set('email_reply', 'reply-fixed@example.com'); + $this->modx->newsletters[10] = $newsletter; + + $queue = new sxQueue($this->modx); + $queue->fromArray(array( + 'id' => 1, + 'newsletter_id' => 10, + 'subscriber_id' => 1, + 'email_to' => 'to@example.com', + 'email_subject' => 'Subject', + 'email_body' => 'Body', + 'email_from' => 'bad-address', + 'email_from_name' => 'Old Name', + 'email_reply' => 'bad-reply', + )); + + $message = sxNewsletterMailer::messageFromQueue($queue); + + $this->assertSame('fixed@example.com', $message['email_from']); + $this->assertSame('Fixed Sender', $message['email_from_name']); + $this->assertSame('reply-fixed@example.com', $message['email_reply']); + $this->assertSame('Subject', $message['email_subject']); + } + public function testSanitizeHeaderStripsControlCharacters() { $this->assertSame('from@example.comBcc:bad@example.com', sxNewsletterMailer::sanitizeHeader("from@example.com\x00Bcc:bad@example.com"));