diff --git a/app/Services/Maintenance/MaintenanceNotifier.php b/app/Services/Maintenance/MaintenanceNotifier.php index a6cfa22..5be9c42 100644 --- a/app/Services/Maintenance/MaintenanceNotifier.php +++ b/app/Services/Maintenance/MaintenanceNotifier.php @@ -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) { diff --git a/tests/Feature/Mail/SenderAddressTest.php b/tests/Feature/Mail/SenderAddressTest.php index 37426f5..1a8f6ac 100644 --- a/tests/Feature/Mail/SenderAddressTest.php +++ b/tests/Feature/Mail/SenderAddressTest.php @@ -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 () {