我使用的是Laravel 5.5。该网站的性质是一个多站点'从同一代码库运行多个网站/域的架构。
发送电子邮件时我遇到了一个问题。我需要更改from
name
和address
以及transport
(SMTP等)选项,具体取决于正在查看的网站。我将这些详细信息存储在配置文件中。
最简单的方法是在调用Mail::send
/ Mail::queue
之前在控制器中提取这些详细信息并进行更新。但是,这会带来两个问题:
Mail::send
代替Mail::queue
,因为队列从 排队 仅限 处理 。我怎样才能以干净的方式实现我的目标?
我考虑过扩展我的所有“Mailable”'具有更新SMTP详细信息的自定义类的类,但看起来您可以在启动类后更新SMTP /传输信息;您只能更新from
name
和address
。
答案 0 :(得分:2)
我设法找到了这样做的方法。
我的mailable类(ContactFormMailable
)扩展了一个自定义类,如下所示:
<?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
。这是在我的扩展类中,用于计算我需要用于邮件的视图和模板,具体取决于正在查看的网站。在这里我还设置了我的配置文件夹的位置。
<?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;
}
}
重要的是要记住邮件可以排队。如果你这样做是另一种方式,比如在运行时设置一个配置,那么你会发现运行队列的进程没有运行时配置更改的可见性/范围,你最终会发出你的电子邮件默认值。
我找到了一些与此相似的答案,这些答案帮助了我,但是没有一个完全有效,有些已经过时了(Swift_SmtpTransport
自那些答案以后发生了很大的变化)。
希望这有助于其他人。