Laravel - changing email settings on the fly is not working

Solution 1:

TL;DR

An immediate answer to your question, please refer to this following code tested on 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');

Why setting up config on the fly does not work?

In laravel architecture, it is first had all the service providers registered and that includes the MailServiceProvider. See your config/app.php

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

And the config will be loaded before it reaches your route, see 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
   }

so the way I deal with this using TransportManager's drivers method to pick up desired driver and set the config I want, since above code we can see lots of usage of its api.

Hope this helps

Solution 2:

I am facing the same issue I just use

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

when I Debug

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

Configuration is all fine

I just review a comment here by kfirba

I'm pretty sure that the issue is caused because when laravel registers the mailer key in the IoC Container it uses the original config. Changing that won't cause laravel to re-define the mailer key. If you take a look at MailerServiceProvider you will see that it is deferred which means that once you call it, it will instantiate the object and it uses a singleton. I believe that you've used the Mail::send() method elsewhere in the application which led to registering the mailer key in the application. Since it's a singleton it won't read your configuration files again when you re-use it.

Solution:

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

Works on Laravel 8