【问题标题】:multiple mail configurations多邮件配置
【发布时间】:2014-12-20 05:26:50
【问题描述】:

我用 mandrill 驱动配置了 laravel 的邮件服务。这里没有问题!

现在,在我申请的某个阶段,我需要通过 gmail 发送邮件。

我做了类似的事情:

// backup current mail configs
$backup = Config::get('mail');

// rewrite mail configs to gmail stmp
$new_configs = array(
    'driver' => 'smtp',
    // ... other configs here
);
Config::set('mail', $new_configs);

// send the email
Mail::send(...

// restore configs
Config::set('mail', $backup);

这不起作用,laravel 总是使用 mandrill 配置。看起来他在脚本启动时启动了邮件服务,并忽略了您在执行期间所做的任何事情。

在执行期间如何更改邮件服务配置/行为?

【问题讨论】:

    标签: laravel laravel-4


    【解决方案1】:

    您可以创建一个新的 Swift_Mailer 实例并使用它:

    // Backup your default mailer
    $backup = Mail::getSwiftMailer();
    
    // Setup your gmail mailer
    $transport = Swift_SmtpTransport::newInstance('smtp.gmail.com', 465, 'ssl');
    $transport->setUsername('your_gmail_username');
    $transport->setPassword('your_gmail_password');
    // Any other mailer configuration stuff needed...
    
    $gmail = new Swift_Mailer($transport);
    
    // Set the mailer as gmail
    Mail::setSwiftMailer($gmail);
    
    // Send your message
    Mail::send();
    
    // Restore your original mailer
    Mail::setSwiftMailer($backup);
    

    【讨论】:

    • 它就像一个魅力。对于那些可能寻找的人,SmtpTransport 来自使用 Swift_SmtpTransport 作为 SmtpTransport;
    • 我用它来区分“常规”电子邮件和“系统”电子邮件。效果很好,谢谢!
    • 这很好,但不适用于Mail::queue($mail),为什么?
    • 使用 Mail::queue 发送的电子邮件是在工作进程上发送的,而不是在您正在切换邮件程序的当前上下文中发送电子邮件,并像这样发送它们,使用作业。
    • @Suge 请在下面查看我的答案,该答案扩展了接受(和正确)的答案。
    【解决方案2】:

    聚会有点晚了,但只是想扩展接受的答案并投入我的 2 美分,以防它节省某人的时间。在我的场景中,每个登录用户都有自己的 SMTP 设置,但我使用队列发送邮件,这导致设置在设置后恢复为默认值。它还产生了一些并发的电子邮件问题。简而言之,问题是

    $transport = Swift_SmtpTransport::newInstance($user->getMailHost(), $user->getMailPort(), $user->getMailEncryption());
    $transport->setUsername($user->getMailUser());
    $transport->setPassword($user->getMailPassword());
    $mailer = new Swift_Mailer($transport);
    Mail::setSwiftMailer($mailer);
    //until this line all good, here is where it gets tricky
    
    Mail::send(new CustomMailable());//this works
    Mail::queue(new CustomMailable());//this DOES NOT WORK
    

    在敲了几下键盘之后,我意识到队列正在一个单独的进程上运行,因此 Mail::setSwiftMailer 根本不会影响它。它只是选择默认设置。 因此,配置更改必须在发送电子邮件的实际时刻发生,而不是在排队时发生。

    我的解决方案是扩展 Mailable 类,如下所示。

    app\Mail\ConfigurableMailable.php
    
    <?php
    
    namespace App\Mail;
    
    use Illuminate\Container\Container;
    use Illuminate\Contracts\Mail\Mailer;
    use Illuminate\Mail\Mailable;
    use Swift_Mailer;
    use Swift_SmtpTransport;
    
    class ConfigurableMailable extends Mailable
    {
        /**
         * Override Mailable functionality to support per-user mail settings
         *
         * @param  \Illuminate\Contracts\Mail\Mailer  $mailer
         * @return void
         */
        public function send(Mailer $mailer)
        {
            $host      = $this->user->getMailHost();//new method I added on User Model
            $port      = $this->user->getMailPort();//new method I added on User Model
            $security  = $this->user->getMailEncryption();//new method I added on User Model
    
            $transport = Swift_SmtpTransport::newInstance( $host, $port, $security);
            $transport->setUsername($this->user->getMailUser());//new method I added on User Model
            $transport->setPassword($this->user->getMailPassword());//new method I added on User Model
            $mailer->setSwiftMailer(new Swift_Mailer($transport));
    
            Container::getInstance()->call([$this, 'build']);
            $mailer->send($this->buildView(), $this->buildViewData(), function ($message) {
                $this->buildFrom($message)
                     ->buildRecipients($message)
                     ->buildSubject($message)
                     ->buildAttachments($message)
                     ->runCallbacks($message);
            });
        }
    }
    

    然后将CustomMail改为扩展ConfigurableMailable而不是Mailable

    class CustomMail extends ConfigurableMailable {}

    这确保即使调用Mail::queue(new CustomMail()) 也会在发送前设置每个用户的邮件设置。当然,您必须在某个时候将当前用户注入 CustomMail,即Mail::queue(new CustomMail(Auth::user()))

    虽然这可能不是理想的解决方案(即,如果尝试发送批量电子邮件,最好只配置一次邮件,而不是在发送的每封电子邮件上),但我喜欢它的简单性以及我们不需要更改全局MailConfig 设置,只有$mailer 实例受到影响。

    希望你觉得它有用!

    【讨论】:

    • 为什么需要为每个用户设置一个唯一的 SMTP 设置?
    • @Adam 主机、端口和加密通常保持不变,但需要用户名和密码才能从 SMTP 服务器检索该用户的电子邮件。你有更好的办法吗?
    • @Adam 是的,它适用于类似 CRM 的应用程序,用户直接与客户端通信,然后应用程序需要监控响应。
    • @dev7 谢谢,这就是我想要的。是我的用例:需要动态设置 smtp 设置的应用程序。节省了大量时间。
    • 对我的不同用例非常有用。 MailGun 服务现在被 hotmail.com、live.com、outlook.com 等微软邮件服务阻止,我需要为我们的微软电子邮件用户使用单独的自定义 SMTP 发件人。我检查了$this-&gt;to,查看电子邮件域是否被阻止,然后使用自定义 Swift_SmtpTransport 实例发送电子邮件。否则我会使用我的默认电子邮件配置,只需调用parent::send($mailer);
    【解决方案3】:

    对于Laravel version 7.x 及更高版本,您现在可以说明在发送电子邮件时要使用的邮件驱动程序。您只需在config/mail.php 中正确配置所有连接和凭据。配置完成后,您可以通过mailer() 函数指定驱动程序的名称,如下所示:

    Mail::mailer('postmark')
        ->to($request->user())
        ->send(new OrderShipped($order));
    

    我希望它对某人有所帮助。

    【讨论】:

    • 感谢更新,确实有帮助,只是一个简短的说明,路径是config/mail.php,没有app/。
    • 对于任何使用旧代码库的人:Laravel 仍然向后兼容 github.com/laravel/framework/blob/…
    【解决方案4】:

    您可以设置即时邮件设置:

    Config::set('mail.encryption','ssl');
    Config::set('mail.host','smtps.example.com');
    Config::set('mail.port','465');
    Config::set('mail.username','youraddress@example.com');
    Config::set('mail.password','password');
    Config::set('mail.from',  ['address' => 'youraddress@example.com' , 'name' => 'Your Name here']);
    

    也许您可以将设置值存储在 config/customMail.php 并通过 Config::get('customMail') 检索它们

    【讨论】:

    • 但它并不总是有效,因为“$app”可能已经定义了。所以不会影响流量。
    • 这对于并发用户同时发送电子邮件或使用队列发送电子邮件时可能无法按预期工作。
    • @yani 您能否解释一下您的评论,为什么这对于并发用户和队列不能按预期工作?
    • @ShankarThiyagaraajan 是的,你是对的,你需要在使用之前定义你的新配置。如何定义邮件配置?在此处查看详细答案stackoverflow.com/a/48382559/4494207
    【解决方案5】:

    对于 Laravel 6,您应该像这样使用它:

    // Backup your default mailer
    $backup = Mail::getSwiftMailer();
    
    // Setup your gmail mailer
    $gmail = new \Swift_SmtpTransport('smtp.gmail.com', 465, 'ssl');
    
    // Set the mailer as gmail
    Mail::setSwiftMailer(new \Swift_Mailer($gmail));
    
    // Send your message
    Mail::send();
    
    // Restore your original mailer
    Mail::setSwiftMailer($backup);
    

    【讨论】:

      【解决方案6】:

      按照 Bogdan 的解释,仅使用 setSwiftMailer 对我不起作用,因为 fromadress 选项仍然取自 config/mail.php。它也不适用于队列。

      我创建了一个名为 multiMail 的包来解决这个问题。

      可以在/config/multimail.php中设置邮件地址和主机/提供商/用户名/密码等,然后可以使用发送邮件

      \MultiMail::from('office@example.com')->send(new MailableDummy()));
      \MultiMail::from('contact@otherdomain.de')->send(new MailableDummy()));
      

      或排队

      \MultiMail::from('office@example.com')->queue(new MailableDummy()));
      

      【讨论】:

      • Office 365 SMTP 重要
      【解决方案7】:

      更容易执行以下代码,就在发送电子邮件之前,之后 你已经用 config 覆盖了邮件配置:

      app()->forgetInstance('swift.transport');
      app()->forgetInstance('swift.mailer');
      app()->forgetInstance('mailer');
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-12-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-11-25
        相关资源
        最近更新 更多