authorize('mail.manage'); } /** * Send one to the signed-in operator. * * To themselves and nobody else — no address field. A preview that can be * addressed is a form for sending mail to strangers from inside the console, * which is not what this is for and not something to leave lying about. */ public function sendToMe(string $key): void { $this->authorize('mail.manage'); $operator = Auth::guard('operator')->user(); $mailable = app(MailPreviews::class)->make($key); if ($operator === null || $mailable === null) { return; } try { // sendNow(), not send(): every mailable here implements ShouldQueue, // and send() silently defers to queue() for those — which would put // a failure in a worker's log while the button reported success. The // person pressing it is waiting for the mail, so the send happens in // their request and its failure reaches them. // // Through the mailable's OWN mailer. Mail::to() hands back a pending // mail bound to the DEFAULT mailer, and sendNow() then ignores the // mailer the mailable asked for — so a support mail addressed // support@ went out over the no-reply@ login and the server answered // "553 Sender address rejected: not owned by user". Every purpose // mailbox here has its own SMTP account, and the From has to belong // to the account that authenticates. Mail::mailer($mailable->mailer ?: null) ->to($operator->email) ->sendNow($mailable); } catch (Throwable $e) { $this->dispatch('notify', message: __('mail_preview.failed', [ 'reason' => mb_substr($e->getMessage(), 0, 160), ])); return; } $this->dispatch('notify', message: __('mail_preview.sent', ['email' => $operator->email])); } public function render() { $this->authorize('mail.manage'); $previews = app(MailPreviews::class)->all(); return view('livewire.admin.mail-preview', [ 'previews' => $previews, // Read off the mailables rather than kept as a second list: the // sender is decided by the purpose mailbox, and a table here would // be a copy that drifts. // From the envelope, not from the mailable's `from` property: that // property stays empty until the mail is built, so reading it here // showed nothing at all. 'senders' => collect($previews) ->keys() ->mapWithKeys(fn (string $key) => [ $key => app(MailPreviews::class)->make($key)?->envelope()->from?->address, ]) ->all(), 'me' => Auth::guard('operator')->user()?->email ?? '', // A preview that goes nowhere is worse than none: with a // non-delivering mailer the browser view still works and the send // silently writes to a file. 'delivers' => ! in_array(config('mail.default'), ['log', 'array', null], true), ]); } }