You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel 8 队列场景下通知Job配置自定义SMTP参数的实现问询

Laravel 多租户动态SMTP配置实现方案

核心逻辑说明

所有配置注入操作必须在队列任务的handle执行阶段完成,不能在控制器分发任务或通知类构造阶段修改配置:

  • 队列任务是异步执行的,控制器阶段修改的配置仅作用于当前请求进程,对独立运行的队列worker进程无效
  • 同一worker进程会顺序处理多个任务,只有在任务执行时动态修改/重置配置,才能避免不同租户的SMTP参数互相串用

具体实现步骤

1. 修改队列任务类 SendNewAnnouncementNotificationJob.php

在任务执行逻辑前先获取当前公告所属公司的SMTP配置,动态覆盖邮件服务配置,重置已初始化的邮件实例后再发送通知:

public function handle()
{
    // 备份全局默认邮件配置,用于任务结束后恢复
    $originalMailConfig = config('mail');
    // 获取当前公告关联的公司SMTP配置,按需调整取数逻辑
    $companySmtp = $this->announcement->company->smtp_config;

    try {
        // 动态覆盖邮件配置
        config([
            'mail.mailers.smtp.host' => $companySmtp['host'],
            'mail.mailers.smtp.port' => $companySmtp['port'],
            'mail.mailers.smtp.username' => $companySmtp['username'],
            'mail.mailers.smtp.password' => $companySmtp['password'],
            'mail.mailers.smtp.encryption' => $companySmtp['encryption'],
            'mail.from.address' => $companySmtp['from_address'],
            'mail.from.name' => $companySmtp['from_name'],
        ]);

        // 清除已缓存的邮件实例,强制用新配置初始化
        app()->forgetInstance('mailer');
        app()->forgetInstance(\Illuminate\Mail\Mailer::class);
        // Laravel 7及以下使用SwiftMailer的话额外加一行
        // app()->forgetInstance('swift.mailer');

        // 原有通知发送逻辑
        foreach ($this->announcement->subscribers as $subscriber) {
            Notification::route('mail', $subscriber->email)
                ->notify(new NewAnnouncement($this->announcement));
        }
    } finally {
        // 恢复全局默认配置,避免影响同worker下的后续任务
        config($originalMailConfig);
        app()->forgetInstance('mailer');
    }
}

2. 可选优化:独立自定义邮件器

如果不想修改默认SMTP配置,也可以动态创建独立的自定义邮件器,再指定通知用该邮件器发送:

// 在Job的handle方法中动态创建自定义邮件器
$customMailer = app('mail.manager')->mailer([
    'transport' => 'smtp',
    'host' => $companySmtp['host'],
    'port' => $companySmtp['port'],
    'username' => $companySmtp['username'],
    'password' => $companySmtp['password'],
    'encryption' => $companySmtp['encryption'],
    'from' => [
        'address' => $companySmtp['from_address'],
        'name' => $companySmtp['from_name'],
    ],
]);

// 修改NewAnnouncement通知类的toMail方法,指定使用对应邮件器
public function toMail($notifiable)
{
    return (new MailMessage)
        ->mailer($this->customMailerName) // 传入自定义邮件器标识
        ->from($this->announcement['sender_name'])
        ->subject('New Announcement at '.$this->announcement['pagename'])
        ->line($this->announcement['text'])
        ->line('Thank you for using our application!');
}

注意事项

  • 通知类的构造方法是在控制器分发任务时执行的,不要在构造方法内修改配置,修改结果不会同步到队列执行环境
  • 如果队列worker配置为单次执行单个任务(--once参数),可以省略配置恢复的逻辑,更稳妥的方案还是保留恢复逻辑避免边界问题
  • 数据库存储SMTP密码时建议做加密处理,不要明文存储

内容的提问来源于stack exchange,提问作者marius

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 14:51:03