mailboxAddresses($purpose, $mailKey); return new Envelope( from: $from, replyTo: $replyTo ? [$replyTo] : [], subject: $subject, ); } /** * The From and Reply-To addresses for $purpose's mailbox — the ONE place * that decides "no configured mailbox means no sender fields at all" and * "no_reply means no Reply-To". Shared by every consumer of a purpose * mailbox regardless of the shape it builds — an Envelope here (a * Mailable), a MailMessage in CloudReady (a Notification, which cannot * use mailboxEnvelope() directly since it is not building an Envelope). * Two independent copies of this same decision is exactly the shape of * gap Task 4 found and fixed in MailboxTransport::resolution(). * * $mailKey names this ONE mail type in MailCatalogue and lets MailRoute * override the purpose's mailbox for it alone. Left null (every caller * before this parameter existed, and every one that still has no reason * to be overridden individually), behaviour is exactly what it was: the * purpose alone decides. * * @return array{0: ?Address, 1: ?Address} [from, replyTo] */ protected function mailboxAddresses(string $purpose, ?string $mailKey = null): array { $box = $mailKey !== null ? MailRoute::purposeOrMailbox($mailKey, $purpose) : app(MailboxResolver::class)->for($purpose); if ($box === null) { // No mailbox configured yet — both null, so a caller falls back // to its own framework default rather than dereferencing null. return [null, null]; } $from = new Address($box->address, $box->display_name ?: null); return [$from, $box->no_reply ? null : $from]; } }