4

我的应用程序的所有电子邮件设置都存储在数据库中。用户可以选择更改这些设置,这一切都很好。但我正在尝试设置“发送测试电子邮件”功能,以允许用户在保存之前测试他们的设置。当他们提交用于发送测试电子邮件的表单时,电子邮件是通过原始设置而不是新设置发送的。

表单提交到 SettingsController.php

//  Send a test email
public function sendTestEmail(Request $request)
{
   Log::info(config('mail.host'));  
   //  Just to check the current email host - shows the proper host 
   //  from the database - i.e. smtp.mailtrap.io

   //  Make sure that all of the information properly validates
   $request->validate([
       'host'       => 'required',
       'port'       => 'required|numeric',
       'encryption' => 'required',
       'username'   => 'required'
   ]);

   //  Temporarily set the email settings
   config([
       'mail.host'       => $request->host,
       'mail.port'       => $request->port,
       'mail.encryption' => $request->encryption,
       'mail.username'   => $request->username,
   ]);
   //  Only update the password if it has been changed
   if(!empty($request->password))
   {
       config(['mail.password' => $request->password]);
   }

   //  Try and send the test email
   try
   {
       Log::info(config('mail.host'));
       //  Just to check the new setting - this also shows the correct
       //  email host - which is the newly assigned one via the form 
       //  i.e. smtp.google.com

       Mail::to(Auth::user()->email)->send(new TestEmail());
       return response()->json([
           'success' => true,
           'sentTo'  => Auth::user()->email
       ]);
   }
   catch(Exception $e)
   {
       Log::notice('Test Email Failed.  Message: '.$e);
       $msg = '['.$e->getCode().'] "'.$e->getMessage().'" on line '.
            $e->getTrace()[0]['line'].' of file '.$e->getTrace()[0]['file'];
       return response()->json(['message' => $msg]);
   }
}

在我的 TestEmail 课程中,我将其归结为基础

namespace App\Mail;

//use Illuminate\Bus\Queueable;  //  Commented out to be sure it is not queuing
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
//use Illuminate\Contracts\Queue\ShouldQueue;  //  Commented out to be sure it is not queuing

class TestEmail extends Mailable
{
//    use Queueable, SerializesModels;  //  Commented out to be sure it is not queuing

 /**
 * Create a new message instance.
 *
 * @return void
 */
public function __construct()
{
    //
}

/**
 * Build the message.
 *
 * @return $this
 */
public function build()
{
    return $this->subject('Test Email From '.config('app.name'))->markdown('email.testEmail');
}
}

即使日志显示配置设置的更新 smtp 主机,消息仍然通过原始设置发送出去 - 即 smtp.mailtrap.io。

4

4 回答 4

3

TL;博士

立即回答您的问题,请参阅在Laravel 5.8上测试的以下代码:

$transport = app('swift.transport');
$smtp = $transport->driver('smpt');
$smpt->setHost('PUT_YOUR_HOST_HERE');
$smpt->setPort('THE_PORT_HERE');
$smpt->setUsername('YOUR_USERNAME_HERE');
$smpt->setPassword('YOUR_PASSWORD_HERE');
$smpt->setEncryption('YOUR_ENCRYPTION_HERE');

为什么即时设置配置不起作用?

在 laravel 架构中,它首先注册了所有服务提供者,其中包括 MailServiceProvider。查看您的config/app.php

    // inside config/app.php
    ...
    Illuminate\Mail\MailServiceProvider::class,
    ...

并且配置将在到达您的路线之前加载,请参阅Illuminate\Mail\TransportManager

    /**
     * Create an instance of the SMTP Swift Transport driver.
     *
     * @return \Swift_SmtpTransport
     */
    protected function createSmtpDriver()
    {
        $config = $this->app->make('config')->get('mail');

        // The Swift SMTP transport instance will allow us to use any SMTP backend
        // for delivering mail such as Sendgrid, Amazon SES, or a custom server
        // a developer has available. We will just pass this configured host.
        $transport = new SmtpTransport($config['host'], $config['port']);

        if (isset($config['encryption'])) {
            $transport->setEncryption($config['encryption']);
        }
        //... rest of the code
   }

所以我使用 TransportManager 的驱动程序方法来处理这个问题来获取所需的驱动程序并设置我想要的配置,因为上面的代码我们可以看到它的 api 的大量使用。

希望这可以帮助

于 2020-02-18T05:27:29.700 回答
1

我面临着我刚刚使用的同样问题

config(['mail.driver' => 'smtp']);

当我调试

dd(config('mail.driver'));

配置一切正常

我只是在这里查看kfirba的评论

我很确定这个问题是因为当 laravel 在 IoC 容器中注册邮件密钥时,它使用了原始配置。更改不会导致 laravel 重新定义邮件密钥。如果您查看 MailerServiceProvider,您会看到它是延迟的,这意味着一旦您调用它,它将实例化对象并使用单例。我相信您已经在应用程序的其他地方使用了 Mail::send() 方法,这导致在应用程序中注册邮件程序密钥。由于它是一个单例,因此当您重新使用它时,它不会再次读取您的配置文件。

解决方案:

config(['mail.driver' => 'smtp']);
(new Illuminate\Mail\MailServiceProvider(app()))->register();

适用于 Laravel 8

于 2021-07-01T12:18:40.963 回答
0

您可以使用 Config::set 即时设置/更改任何配置:

Config::set('key', 'value'); 因此,要设置/更改 mail.php 中的端口,您可以尝试以下操作:

Config::set('mail.port', 587); // default

注意:运行时设置的配置值只针对当前请求设置,不会延续到后续请求

于 2019-03-30T06:24:59.737 回答
0

当您的应用实例发送第一封电子邮件时,Laravel MailManager 会使用当前配置值解析一个新的邮件程序,并通过将其添加到内部邮件程序数组来缓存它。在您发送的每封后续邮件中,将使用相同的缓存邮件程序。

MailManager 有一个清除邮件缓存的方法:

Mail::forgetMailers();

现在,当您发送另一封邮件时,MailManager 必须解析一个新的邮件程序,并且在这样做时它会重新读取您的配置。

于 2022-01-21T08:21:43.113 回答