Laravel: 是否可以延迟发送通知,但动态更改 smtp 设置?
Laravel: Is possible send notification with delay, but changing smtp settings dynamically?
我正在使用 Laravel v5.7 开发一个多租户(多数据库)并且我成功地发送了队列电子邮件。
在某些特定情况下,我想使用 'delay' 发送按需通知,类似于指南 On-Demand Notifications,但在发送前通知应该使用的 SMTP 设置。
我开发了一个 class 来改变 config() 的值。
app/Tenant/SmtpConfig.php
class SmtpConfig
{
public static function setConnection(SmtpConta $conta = null)
{
// get connection default settings
$config = config()->get("mail");
// populate connection default settings
foreach ($config as $key => $value) {
if ( $key == 'host' ) { $config[$key] = $conta->mail_host ?? $config[$key]; }
if ( $key == 'from' ) { $config[$key] = [
'address' => ( $conta->mail_host === 'smtp.mailtrap.io' ) ? $config[$key]['address'] : $conta->mail_username,
'name' => $conta->conta ?? $config[$key]['name']
]; }
if ( $key == 'username' ) { $config[$key] = $conta->mail_username ?? $config[$key]; }
if ( $key == 'password' ) { $config[$key] = !empty($conta->mail_password) ? $conta->mail_password : $config[$key]; }
}
$config['encryption'] = ( $conta->mail_host === 'smtp.mailtrap.io' ) ? null : 'ssl';
// set connection default settings
config()->set("mail", $config);
}
}
... 我在通知中称此为 SmtpConfig class:
/**
* Create a new notification instance.
*
* @param $conta
* @param $subject
* @return void
*/
public function __construct(SmtpConta $conta = null, $subject = null)
{
$this->conta = $conta;
$this->subject = $subject;
$when = \Carbon\Carbon::now()->addSecond(100);
$this->delay($when);
app(\App\Tenant\SmtpConfig::class)::setConnection($this->conta);
}
我可以成功发送 'delayed' 通知,但显然它总是使用 .env
文件的默认值。
现在我不确定我在哪里调用 class 是否有意义,甚至不确定我如何告诉通知它应该使用什么 SMTP 配置。
我想你也可以参考这个实现
您可以通过传递自定义 smtp 配置来执行。
$transport = new Swift_SmtpTransport(
$customSmtp->host,
$customSmtp->port,
$customSmtp->encryption
);
我目前在使用 Notification backport 库的 Laravel 5.2 代码库上面临类似的挑战。
这是我的解决方案示例,类似于 Kit Loong 的建议。我们只是扩展 Illuminate\Notifications\Channels\MailChannel
class 并覆盖 send()
方法。
您需要能够确定收件人或通知对象的 SMTP 配置,因此您需要根据需要编辑我的示例。
此外,这假设您的应用使用默认 Swift_Mailer
所以 YMMV...
<?php
declare (strict_types = 1);
namespace App\Notifications\Channels;
use Illuminate\Notifications\Channels\MailChannel;
use Illuminate\Notifications\Notification;
class DynamicSmtpMailChannel extends MailChannel
{
/**
* Send the given notification.
*
* @param mixed $notifiable
* @param \Illuminate\Notifications\Notification $notification
* @return void
*/
public function send($notifiable, Notification $notification)
{
//define this method on your model (note $notifiable could be an array or collection of notifiables!)
$customSmtp = $notifiable->getSmtpConfig();
if ($customSmtp) {
$previousSwiftMailer = $this->mailer->getSwiftMailer();
$swiftTransport = new \Swift_SmtpTransport(
$customSmtp->smtp_server,
$customSmtp->smtp_port,
$customSmtp->smtp_encryption
);
$swiftTransport->setUsername($customSmtp->smtp_user);
$swiftTransport->setPassword($customSmtp->smtp_password);
$this->mailer->setSwiftMailer(new \Swift_Mailer($swiftTransport));
}
$result = parent::send($notifiable, $notification);
if (isset($previousSwiftMailer)) {
//restore the previous mailer
$this->mailer->setSwiftMailer($previousSwiftMailer);
}
return $result;
}
}
临时存储自定义 swift 邮件程序也可能是有益的,这样您就可以在同一个 invokation/request 中重复使用它们(考虑长期 运行 工作人员) - 就像一个集合 class,其中 smtp 配置的散列用作项目键。
祝你好运。
编辑:
我应该提一下你可能需要在服务容器中绑定它。这样的东西应该足够了:
// in a service provider
public function register()
{
$this->app->bind(
\Illuminate\Notifications\Channels\MailChannel::class
\App\Notifications\Channels\DynamicSmtpMailChannel::class
);
}
或者,将其注册为单独的通知渠道。
我正在使用 Laravel v5.7 开发一个多租户(多数据库)并且我成功地发送了队列电子邮件。
在某些特定情况下,我想使用 'delay' 发送按需通知,类似于指南 On-Demand Notifications,但在发送前通知应该使用的 SMTP 设置。
我开发了一个 class 来改变 config() 的值。
app/Tenant/SmtpConfig.php
class SmtpConfig
{
public static function setConnection(SmtpConta $conta = null)
{
// get connection default settings
$config = config()->get("mail");
// populate connection default settings
foreach ($config as $key => $value) {
if ( $key == 'host' ) { $config[$key] = $conta->mail_host ?? $config[$key]; }
if ( $key == 'from' ) { $config[$key] = [
'address' => ( $conta->mail_host === 'smtp.mailtrap.io' ) ? $config[$key]['address'] : $conta->mail_username,
'name' => $conta->conta ?? $config[$key]['name']
]; }
if ( $key == 'username' ) { $config[$key] = $conta->mail_username ?? $config[$key]; }
if ( $key == 'password' ) { $config[$key] = !empty($conta->mail_password) ? $conta->mail_password : $config[$key]; }
}
$config['encryption'] = ( $conta->mail_host === 'smtp.mailtrap.io' ) ? null : 'ssl';
// set connection default settings
config()->set("mail", $config);
}
}
... 我在通知中称此为 SmtpConfig class:
/**
* Create a new notification instance.
*
* @param $conta
* @param $subject
* @return void
*/
public function __construct(SmtpConta $conta = null, $subject = null)
{
$this->conta = $conta;
$this->subject = $subject;
$when = \Carbon\Carbon::now()->addSecond(100);
$this->delay($when);
app(\App\Tenant\SmtpConfig::class)::setConnection($this->conta);
}
我可以成功发送 'delayed' 通知,但显然它总是使用 .env
文件的默认值。
现在我不确定我在哪里调用 class 是否有意义,甚至不确定我如何告诉通知它应该使用什么 SMTP 配置。
我想你也可以参考这个实现
您可以通过传递自定义 smtp 配置来执行。
$transport = new Swift_SmtpTransport(
$customSmtp->host,
$customSmtp->port,
$customSmtp->encryption
);
我目前在使用 Notification backport 库的 Laravel 5.2 代码库上面临类似的挑战。
这是我的解决方案示例,类似于 Kit Loong 的建议。我们只是扩展 Illuminate\Notifications\Channels\MailChannel
class 并覆盖 send()
方法。
您需要能够确定收件人或通知对象的 SMTP 配置,因此您需要根据需要编辑我的示例。
此外,这假设您的应用使用默认 Swift_Mailer
所以 YMMV...
<?php
declare (strict_types = 1);
namespace App\Notifications\Channels;
use Illuminate\Notifications\Channels\MailChannel;
use Illuminate\Notifications\Notification;
class DynamicSmtpMailChannel extends MailChannel
{
/**
* Send the given notification.
*
* @param mixed $notifiable
* @param \Illuminate\Notifications\Notification $notification
* @return void
*/
public function send($notifiable, Notification $notification)
{
//define this method on your model (note $notifiable could be an array or collection of notifiables!)
$customSmtp = $notifiable->getSmtpConfig();
if ($customSmtp) {
$previousSwiftMailer = $this->mailer->getSwiftMailer();
$swiftTransport = new \Swift_SmtpTransport(
$customSmtp->smtp_server,
$customSmtp->smtp_port,
$customSmtp->smtp_encryption
);
$swiftTransport->setUsername($customSmtp->smtp_user);
$swiftTransport->setPassword($customSmtp->smtp_password);
$this->mailer->setSwiftMailer(new \Swift_Mailer($swiftTransport));
}
$result = parent::send($notifiable, $notification);
if (isset($previousSwiftMailer)) {
//restore the previous mailer
$this->mailer->setSwiftMailer($previousSwiftMailer);
}
return $result;
}
}
临时存储自定义 swift 邮件程序也可能是有益的,这样您就可以在同一个 invokation/request 中重复使用它们(考虑长期 运行 工作人员) - 就像一个集合 class,其中 smtp 配置的散列用作项目键。
祝你好运。
编辑: 我应该提一下你可能需要在服务容器中绑定它。这样的东西应该足够了:
// in a service provider
public function register()
{
$this->app->bind(
\Illuminate\Notifications\Channels\MailChannel::class
\App\Notifications\Channels\DynamicSmtpMailChannel::class
);
}
或者,将其注册为单独的通知渠道。