Keep the purpose mailer through the queue instead of losing it to the default
Mail::to($x)->queue($mail) resolves the DEFAULT mailer, and
Illuminate\Mail\Mailer::queue() (vendor Mailer.php:482) does
`$view->mailer($this->name)->queue($this->queue)` — overwriting
MaintenanceAnnouncementMail/MaintenanceCancelledMail's own 'cp_maintenance'
with the default mailer's name ('array' in tests, 'log'/whatever
MAIL_MAILER is in prod) before the job is even built. Both mails kept
sending through the old .env account instead of MailboxTransport. CloudReady
was never affected — MailChannel.php:66 preserves a notification's own
mailer.
Fix: name the mailer before queueing — Mail::mailer($mail->mailer)->to(...).
$this->name on the resolved Mailer is then already $mail->mailer, so the
vendor overwrite becomes a no-op instead of a silent downgrade. Confirmed by
reading the vendor source, not assumed.
SenderAddressTest's "names the purpose mailer..." test asserted
$mail->mailer on a bare, never-queued mailable, which proves nothing about
what survives queueing — the constructor sets it right regardless of what
MaintenanceNotifier does with it. Replaced it with one that drives
MaintenanceNotifier::deliver() under Queue::fake() and inspects the pushed
SendQueuedMailable's mailable. Verified it fails against the pre-fix code
first (the pushed job carried mailer = 'array'), then verified the fix
makes it pass, then mutated the fix away and watched it fail again.
feat/mailboxes
parent
99b7393361
commit
7102d01bcc
|
|
@ -80,7 +80,14 @@ class MaintenanceNotifier
|
|||
|
||||
$mail->notificationId = $delivery->id;
|
||||
try {
|
||||
Mail::to($customer->email)
|
||||
// Mail::to() alone resolves the DEFAULT mailer. Illuminate\Mail\Mailer::queue()
|
||||
// then runs `$view->mailer($this->name)->queue(...)` — that overwrites the
|
||||
// mailable's own purpose mailer (set in its constructor, e.g. 'cp_maintenance')
|
||||
// with the default's name before the job is even built. Naming the mailer here
|
||||
// makes that overwrite a no-op: $this->name on the resolved Mailer is already
|
||||
// $mail->mailer, so it writes back the same value.
|
||||
Mail::mailer($mail->mailer)
|
||||
->to($customer->email)
|
||||
->locale($customer->locale ?: config('app.locale'))
|
||||
->queue($mail);
|
||||
} catch (\Throwable $e) {
|
||||
|
|
|
|||
|
|
@ -8,8 +8,11 @@ use App\Models\Mailbox;
|
|||
use App\Models\MaintenanceWindow;
|
||||
use App\Notifications\CloudReady;
|
||||
use App\Services\Mail\MailPurpose;
|
||||
use App\Services\Maintenance\MaintenanceNotifier;
|
||||
use App\Support\Settings;
|
||||
use Illuminate\Mail\SendQueuedMailable;
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
use Illuminate\Support\Facades\Queue;
|
||||
|
||||
beforeEach(function () {
|
||||
config()->set('admin_access.secrets_key', 'base64:'.base64_encode(random_bytes(32)));
|
||||
|
|
@ -61,12 +64,33 @@ it('sets Reply-To on an answerable mailbox, so a customer reply reaches a human'
|
|||
});
|
||||
|
||||
it('names the purpose mailer so the queue worker picks the right transport', function () {
|
||||
$mail = new MaintenanceAnnouncementMail(
|
||||
MaintenanceWindow::factory()->create(),
|
||||
Customer::factory()->create(),
|
||||
// A bare, never-queued mailable proves nothing here: the constructor sets
|
||||
// $this->mailer correctly regardless of what MaintenanceNotifier does.
|
||||
// Illuminate\Mail\Mailer::queue() (vendor Mailer.php) runs
|
||||
// `$view->mailer($this->name)->queue(...)` — if MaintenanceNotifier queues
|
||||
// through the bare `Mail` facade instead of `Mail::mailer($mail->mailer)`,
|
||||
// that resolves the DEFAULT mailer ('array' in tests) and overwrites the
|
||||
// mailable's own 'cp_maintenance' with it BEFORE the queued job is even
|
||||
// built. The only way to see that is to actually queue it and inspect the
|
||||
// job that comes out the other side.
|
||||
Mailbox::factory()->create(['key' => 'no-reply', 'address' => 'no-reply@clupilot.com', 'no_reply' => true]);
|
||||
Settings::set(MailPurpose::settingKey(MailPurpose::MAINTENANCE), 'no-reply');
|
||||
|
||||
Queue::fake();
|
||||
|
||||
$window = MaintenanceWindow::factory()->create();
|
||||
$customer = Customer::factory()->create();
|
||||
|
||||
app(MaintenanceNotifier::class)->deliver(
|
||||
$window,
|
||||
$customer,
|
||||
'announcement',
|
||||
new MaintenanceAnnouncementMail($window, $customer),
|
||||
);
|
||||
|
||||
expect($mail->mailer)->toBe('cp_maintenance');
|
||||
Queue::assertPushed(SendQueuedMailable::class, function (SendQueuedMailable $job) {
|
||||
return $job->mailable->mailer === 'cp_maintenance';
|
||||
});
|
||||
});
|
||||
|
||||
it('gives the cancellation mail the same sender as the announcement', function () {
|
||||
|
|
|
|||
Loading…
Reference in New Issue