clusev/app/Support/MailSettings.php

69 lines
2.8 KiB
PHP

<?php
namespace App\Support;
use App\Models\Setting;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\Mail;
use Throwable;
/**
* Applies the operator's DB-stored SMTP settings (Settings\Email) to runtime config. ONE shared
* entry point for every process shape:
*
* - web request → AppServiceProvider::boot() (per request)
* - queue worker → Queue::before hook (per job)
* - LONG-LIVED loops → AlertNotifier::notify() (per notification)
*
* The last one matters most: the metrics poller (clusev:poll-metrics under supervisor) runs for
* days. Laravel bakes the DEFAULT MAILER NAME into a mailable at Mail::to()->queue() time, so a
* loop that booted before SMTP was configured would bake `log` into every alert mail forever —
* the worker then "sends" them into laravel.log no matter how correct its own config is. Applying
* fresh settings immediately before queueing bakes the right mailer name.
*
* Mail::purge() drops the cached mailer instance so a config change actually rebuilds the
* transport in long-lived processes instead of reusing the old connection.
*/
class MailSettings
{
public static function apply(): void
{
try {
$host = Setting::get('mail_host');
$from = Setting::get('mail_from_address');
if ($host === null || $host === '' || $from === null || $from === '') {
return; // unconfigured -> keep the safe default mailer
}
$encryption = Setting::get('mail_encryption', 'tls');
$storedPassword = Setting::get('mail_password');
$password = null;
if ($storedPassword !== null && $storedPassword !== '') {
$password = Crypt::decryptString($storedPassword);
}
$changed = config('mail.default') !== 'smtp'
|| config('mail.mailers.smtp.host') !== $host;
config([
'mail.default' => 'smtp',
'mail.mailers.smtp.host' => $host,
'mail.mailers.smtp.port' => (int) (Setting::get('mail_port', '587') ?? 587),
'mail.mailers.smtp.username' => Setting::get('mail_username') ?: null,
'mail.mailers.smtp.password' => $password ?: null,
'mail.mailers.smtp.encryption' => $encryption === 'none' ? null : $encryption,
'mail.from.address' => $from,
'mail.from.name' => Setting::get('mail_from_name') ?: $from,
]);
if ($changed) {
Mail::purge('smtp'); // rebuild the cached transport with the new settings
}
} catch (Throwable) {
// Settings table not migrated yet (install/migrate) or an undecryptable value —
// leave the default mailer untouched. Never break the caller.
}
}
}