lollypopgr's avatar

Mail.driver change on runtime, is being ignored!

I have a very strange problem. I am trying to change the mail driver on runtime. I have a conditional and immediately before Mail::send() I put this line

Config::set('mail.driver','mandrill');

Mail::send() ignores my set and uses the default one. I checked the settings of Mandrill ( made that the default) and worked fine, also verified with Config::get() after the send() that its indeed set to mandrill.

Any idea what to look here?

0 likes
14 replies
Viking's avatar

try Config::set('mail.driver','mandrill'); dd(Config::get('mail.driver'))

just after you change the mail driver and see if it gets changed ...

kfirba's avatar

@lollypopgr 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.

I'm not sure it's gonna work but try to do the following:

Config::set('mailer.driver', 'mandrill');
app()['mailer'] = null;

I think that if we force the mailer to be null the application will build the mailer again using the new settings.

lollypopgr's avatar

No, It returns an error instead

 Symfony \ Component \ Debug \ Exception \ FatalErrorException (E_ERROR)
Call to a member function send() on a non-object 
lollypopgr's avatar

Nothing changed even when setting it in the global "before" filter.

laloutre's avatar

I'm running the same issue, except I'm trying to change the mail driver in the global config (updating .env file at runtime).

With artisan tinker, I can trace the actual mail driver config, and it's the good one (mandrill). But from the website, I'm still using smtp... Very strange.

kfirba's avatar

@lollypopgr Can you try:

Config::set('mailer.driver', 'mandrill');
unset(app()['mailer']);

If it doesn't work, I think we will have to call to the register method on the MailServiceProvider

laloutre's avatar

Oh, OK, this was obvious: I was using queues. I simply restarted the queue worker, and all is good now.

laloutre's avatar

@lollypopgr are you using queues for sending emails? (in case you missed my post above)

If yes, simply restart the queue worker.

lollypopgr's avatar

I use Mail::send() not Mail::queue(). It is fired immediately.

kfirba's avatar
kfirba
Best Answer
Level 50

@lollypopgr Try:

Config::set('mail.driver', 'mandrill');
(new Illuminate\Mail\MailServiceProvider(app()))->register();   

P.S. I just realised that in my solution I told you to alter the mailer.driver instead of mail.driver. Try my other attempts before this post again to see maybe it actually works.

7 likes
lollypopgr's avatar

Thanks a lot, that fixed it completely. Learned something new today :-)

pakogn's avatar

Hi!

yo may provide a swift mailer to the laravel mailer.

<?php

$transport = (new \Swift_SmtpTransport('host', 'port'))
    ->setEncryption(null)
    ->setUsername('username')
    ->setPassword('secret');

$mailer = app(\Illuminate\Mail\Mailer::class);
$mailer->setSwiftMailer(new \Swift_Mailer($transport));

$mail = $mailer
    ->to('[email protected]')
    ->send(new OrderShipped);

Please or to participate in this conversation.