Несколько почтовых конфигураций

Я настроил почтовую службу laravel с драйвером mandrill. Здесь нет проблем!

Теперь, в какой-то момент моего приложения, мне нужно отправить почту через 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 всегда использует конфигурации мандрайров. Похоже, он инициирует почтовую службу при запуске script и игнорирует все, что вы делаете во время выполнения.

Как вы изменяете конфигурацию/поведение почтовых служб во время выполнения?

Ответ 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);

Ответ 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 в какой-то момент i.e Mail::queue(new CustomMail(Auth::user()))

Хотя это не может быть идеальным решением (т.е. при попытке отправить массовую электронную почту лучше настроить почтовую программу один раз, а не на каждое отправленное электронное письмо), мне нравится его простота и тот факт, что нам не нужно менять глобальные настройки Mail или Config вообще, затрагивается только экземпляр $mailer.

Надеюсь, вы сочтете это полезным!

Ответ 3

Вы можете установить настройки "fly fly":

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

Возможно, вы можете сохранить значения настроек в config/customMail.php и извлечь их с помощью Config:: get ('customMail')

Ответ 4

Использование только setSwiftMailer, как объяснил Богдан, не сработало для меня, потому что тогда опции from и adress все еще взяты из config/mail.php. Также это не работало с очередями.

Я создал пакет под названием multiMail, чтобы решить эту проблему.

Можно настроить почтовый адрес и хост/провайдера/имя пользователя/пароль и т.д. В /config/multimail.php, а затем отправлять письма, используя

\MultiMail::from('[email protected]')->send(new MailableDummy()));
\MultiMail::from('[email protected]')->send(new MailableDummy()));

или поставь в очередь

\MultiMail::from('[email protected]')->queue(new MailableDummy()));

Ответ 5

Еще проще выполнить следующий код, непосредственно перед отправкой электронного письма, после того как вы переписали конфигурацию почты с помощью config:

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