如何在运行时全局更改 SMTP 详细信息?
How can I change SMTP details globally at runtime?
我正在使用 Laravel 5.5。该网站的性质是 'multisite' 架构,其中多个 websites/domains 来自同一代码库 运行。
我在发送电子邮件时遇到了问题。我需要根据正在查看的网站更改 from
name
和 address
以及 transport
(SMTP 等)选项。我将这些详细信息存储在配置文件中。
最简单的方法是在我调用 Mail::send
/Mail::queue
之前将这些详细信息拉入控制器并更新它们。然而,这又带来了 2 个问题:
- 每次我在代码中发送任何电子邮件时,都非常依赖于记住实际执行此操作。总之就是不遵守DRY
- 我将被迫使用
Mail::send
而不是 Mail::queue
,因为队列从 [= 开始就不知道配置更新了31=]queued 仅在 processed .
我怎样才能以干净的方式实现我在这里想要做的事情?
我考虑过使用更新 SMTP 详细信息的自定义 class 扩展我的所有 'Mailable' classes,但看起来您无法更新 [= class启动后的48=]信息;您只能更新 from
name
和 address
.
我设法找到了一种方法。
我有我的可邮寄 class (ContactFormMailable
) 扩展自定义 class,如下:
<?php
namespace CustomGlobal\Mail;
use CustomGlobal\Mail\CustomMailable;
use CustomGlobal\ContactForm;
class ContactFormMailable extends CustomMailable
{
public $contact_form;
/**
* Create a new message instance.
*
* @return void
*/
public function __construct(ContactForm $contact_form)
{
$this->contact_form = $contact_form;
}
/**
* Build the message.
*
* @return $this
*/
public function build()
{
$view = $this->get_custom_mail_view('contact_form', $this->contact_form);
return $this->subject('Contact Form Enquiry')
->view($view);
}
}
你会注意到我正在打电话 get_custom_mail_view
。这在我的扩展 class 中,用于计算我需要用于邮件的视图和模板,具体取决于正在查看的网站。在这里我还设置了我的配置文件夹的位置。
<?php
namespace CustomGlobal\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Contracts\Mail\Mailer;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;
use Swift_Mailer;
use Swift_SmtpTransport;
use CustomGlobal\Website;
use CustomGlobal\Territory;
class CustomMailable extends Mailable
{
use Queueable, SerializesModels;
public $layout_view_to_serve;
public $host_folder;
/**
* Override Mailable functionality to support per-user mail settings
*
* @param \Illuminate\Contracts\Mail\Mailer $mailer
* @return void
*/
public function send(Mailer $mailer)
{
app()->call([$this, 'build']);
$config = config($this->host_folder .'.mail');
// Set SMTP details for this host
$host = $config['host'];
$port = $config['port'];
$encryption = $config['encryption'];
$transport = new Swift_SmtpTransport( $host, $port, $encryption );
$transport->setUsername($config['username']);
$transport->setPassword($config['password']);
$mailer->setSwiftMailer(new Swift_Mailer($transport));
$mailer->send($this->buildView(), $this->buildViewData(), function ($message) use($config) {
$message->from([$config['from']['address'] => $config['from']['name']]);
$this->buildFrom($message)
->buildRecipients($message)
->buildSubject($message)
->buildAttachments($message)
->runCallbacks($message);
});
}
/**
* Calculate the template we need to serve.
* $entity can be any object but it must contain a
* $website_id and $territory_id, as that is used
* to calculate the path.
*/
public function get_custom_mail_view($view_filename, $entity)
{
if(empty($view_filename)) {
throw new Exception('The get_custom_mail_view method requires a view to be passed as parameter 1.');
}
if(empty($entity->website_id) || empty($entity->territory_id)) {
throw new Exception('The get_custom_mail_view method must be passed an object containing a website_id and territory_id value.');
}
// Get the website and territory
$website = Website::findOrFail($entity->website_id);
$territory = Territory::findOrFail($entity->territory_id);
$view_to_serve = false;
$layout_view_to_serve = false;
// Be sure to replace . with _, as Laravel doesn't play nice with dots in folder names
$host_folder = str_replace('.', '_', $website->website_domain);
$this->host_folder = $host_folder; // Used for mail config later
/***
Truncated for readability. What's in this area isn't really important to this answer.
***/
$this->layout_view_to_serve = $layout_view_to_serve;
return $view_to_serve;
}
}
重要的是要记住邮件可以排队。如果你这样做是另一种方式,比如在运行时设置配置,那么你会发现运行队列的进程没有 visibility/scope 你的运行时配置更改,你最终会发送电子邮件从您的默认值。
我找到了一些与此类似的答案,这对我有所帮助,但其中 none 完全有效,有些是 out-dated(Swift_SmtpTransport
自从那些答案)。
希望这对其他人有所帮助。
我正在使用 Laravel 5.5。该网站的性质是 'multisite' 架构,其中多个 websites/domains 来自同一代码库 运行。
我在发送电子邮件时遇到了问题。我需要根据正在查看的网站更改 from
name
和 address
以及 transport
(SMTP 等)选项。我将这些详细信息存储在配置文件中。
最简单的方法是在我调用 Mail::send
/Mail::queue
之前将这些详细信息拉入控制器并更新它们。然而,这又带来了 2 个问题:
- 每次我在代码中发送任何电子邮件时,都非常依赖于记住实际执行此操作。总之就是不遵守DRY
- 我将被迫使用
Mail::send
而不是Mail::queue
,因为队列从 [= 开始就不知道配置更新了31=]queued 仅在 processed .
我怎样才能以干净的方式实现我在这里想要做的事情?
我考虑过使用更新 SMTP 详细信息的自定义 class 扩展我的所有 'Mailable' classes,但看起来您无法更新 [= class启动后的48=]信息;您只能更新 from
name
和 address
.
我设法找到了一种方法。
我有我的可邮寄 class (ContactFormMailable
) 扩展自定义 class,如下:
<?php
namespace CustomGlobal\Mail;
use CustomGlobal\Mail\CustomMailable;
use CustomGlobal\ContactForm;
class ContactFormMailable extends CustomMailable
{
public $contact_form;
/**
* Create a new message instance.
*
* @return void
*/
public function __construct(ContactForm $contact_form)
{
$this->contact_form = $contact_form;
}
/**
* Build the message.
*
* @return $this
*/
public function build()
{
$view = $this->get_custom_mail_view('contact_form', $this->contact_form);
return $this->subject('Contact Form Enquiry')
->view($view);
}
}
你会注意到我正在打电话 get_custom_mail_view
。这在我的扩展 class 中,用于计算我需要用于邮件的视图和模板,具体取决于正在查看的网站。在这里我还设置了我的配置文件夹的位置。
<?php
namespace CustomGlobal\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Contracts\Mail\Mailer;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;
use Swift_Mailer;
use Swift_SmtpTransport;
use CustomGlobal\Website;
use CustomGlobal\Territory;
class CustomMailable extends Mailable
{
use Queueable, SerializesModels;
public $layout_view_to_serve;
public $host_folder;
/**
* Override Mailable functionality to support per-user mail settings
*
* @param \Illuminate\Contracts\Mail\Mailer $mailer
* @return void
*/
public function send(Mailer $mailer)
{
app()->call([$this, 'build']);
$config = config($this->host_folder .'.mail');
// Set SMTP details for this host
$host = $config['host'];
$port = $config['port'];
$encryption = $config['encryption'];
$transport = new Swift_SmtpTransport( $host, $port, $encryption );
$transport->setUsername($config['username']);
$transport->setPassword($config['password']);
$mailer->setSwiftMailer(new Swift_Mailer($transport));
$mailer->send($this->buildView(), $this->buildViewData(), function ($message) use($config) {
$message->from([$config['from']['address'] => $config['from']['name']]);
$this->buildFrom($message)
->buildRecipients($message)
->buildSubject($message)
->buildAttachments($message)
->runCallbacks($message);
});
}
/**
* Calculate the template we need to serve.
* $entity can be any object but it must contain a
* $website_id and $territory_id, as that is used
* to calculate the path.
*/
public function get_custom_mail_view($view_filename, $entity)
{
if(empty($view_filename)) {
throw new Exception('The get_custom_mail_view method requires a view to be passed as parameter 1.');
}
if(empty($entity->website_id) || empty($entity->territory_id)) {
throw new Exception('The get_custom_mail_view method must be passed an object containing a website_id and territory_id value.');
}
// Get the website and territory
$website = Website::findOrFail($entity->website_id);
$territory = Territory::findOrFail($entity->territory_id);
$view_to_serve = false;
$layout_view_to_serve = false;
// Be sure to replace . with _, as Laravel doesn't play nice with dots in folder names
$host_folder = str_replace('.', '_', $website->website_domain);
$this->host_folder = $host_folder; // Used for mail config later
/***
Truncated for readability. What's in this area isn't really important to this answer.
***/
$this->layout_view_to_serve = $layout_view_to_serve;
return $view_to_serve;
}
}
重要的是要记住邮件可以排队。如果你这样做是另一种方式,比如在运行时设置配置,那么你会发现运行队列的进程没有 visibility/scope 你的运行时配置更改,你最终会发送电子邮件从您的默认值。
我找到了一些与此类似的答案,这对我有所帮助,但其中 none 完全有效,有些是 out-dated(Swift_SmtpTransport
自从那些答案)。
希望这对其他人有所帮助。