问题描述
我正在制作一个使用 SwiftMail 扩展发送的控制台应用程序.由于我们的政策,我有两台虚拟机,一台用作 SMTP 中继,另一台用作应用程序服务器.通过 telnet 手动向中继发送邮件工作正常.使用 SwiftMail 时,它坏了.
I am making a console application which uses the SwiftMail extension to send. Due to our policy, I have two virtual machines, one which serves as a SMTP relay and the other which is the application server. Sending mail manually through telnet to the relay works fine. When using SwiftMail, it's broken.
返回标头,send()
getHeaders()->toString()
Message-ID: <[email protected]>
Date: Wed, 24 Oct 2012 14:50:31 -0400
Subject: [YourSite] Feedback
From: [email protected]
To: [email protected]
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
如果我回显 send()
,我得到 1
.
If I echo the send()
, i get 1
.
boot.php
$app->register(new Silex\Provider\SwiftmailerServiceProvider(), array(
'swiftmailer.options' => array(
'host' => 'ip.host.relay',
'port' => 25,
'encryption' => null,
'auth_mode' => null
),
));
app.php
$message = \Swift_Message::newInstance( )
->setSubject('[YourSite] Feedback')
->setFrom(array('[email protected]'))
->setTo(array('[email protected]'))
->setBody("Message!");
$app['mailer']->send($message, $failures);
当我在应用服务器上运行 TCP 转储并运行脚本时,没有建立 SMTP 连接,也没有抛出任何错误.
When i run a TCP dump on the app server and run the script, there are no SMTP connection made, and there are no errors thrown.
有人遇到过这种情况吗?由于我们的应用程序要求,我不想使用 sendmail 或邮件,而是使用 SMTP.
Anyone encounter this before? I don't want to use sendmail or mail, but SMTP due to our application requirements.
推荐答案
这是因为 SwiftmailerServiceProvider
默认使用 Swift_MemorySpool
,并且只在 上刷新内核.终止
.让我退后一步解释这其中的每一部分.
This is because the SwiftmailerServiceProvider
uses a Swift_MemorySpool
by default, and only flushes that on kernel.terminate
. Let me take a step back and explain each part of this.
SwiftmailerServiceProvider
负责注册 Swiftmailer 服务和默认配置.默认情况下,传输 (swiftmailer.spooltransport
) 是Swift_SpoolTransport
而swiftmailer.spool
是Swift_MemorySpool
.
The
SwiftmailerServiceProvider
is responsible for registering the Swiftmailer services and default configuration. By default the transport (swiftmailer.spooltransport
) isSwift_SpoolTransport
and theswiftmailer.spool
isSwift_MemorySpool
.
Swiftmailer 支持不同的邮件发送方式.这些被称为传输.线轴传输充当队列.您可以将此队列存储在文件或内存中.假脱机传输有一个 flushQueue
方法,它允许将排队的邮件刷新到一个真正的传输,它应该传递它们.
Swiftmailer supports different ways of sending the mails. These are called transports. The spool transport acts as a queue. You can either store this queue in a file or in memory. Spool transports have a flushQueue
method which allows flushing the queued mails to a real transport, which should deliver them.
Silex 使用的 Symfony2 HttpKernel 在每个请求的生命周期内发出许多事件.它发出的最后一个是 kernel.terminate
事件.此事件在 HTTP 响应正文发送后触发.这允许您在呈现页面后执行繁重的任务,从而不再向用户显示正在加载.
The Symfony2 HttpKernel which Silex uses emits a number of events during the lifecycle of every request. The last one that it emits is the kernel.terminate
event. This event is triggered after the HTTP response body has been sent. This allows you to do heavy tasks after rendering the page, so that it no longer appears as loading to the user.
SwiftmailerServiceProvider
订阅 kernel.terminate
事件,以便在页面呈现后刷新内存假脱机.它将它刷新到 swiftmailer.transport
服务,这是一个 Swift_Transport_EsmtpTransport
,它通过 SMTP 进行实际发送.
The SwiftmailerServiceProvider
subscribes to the kernel.terminate
event in order to flush the memory spool after the page has been rendered. It flushes it to swiftmailer.transport
service, which is a Swift_Transport_EsmtpTransport
that does the actual sending via SMTP.
那么让我们来解决实际问题.您处于 CLI 上下文中,因此不会触发任何 HttpKernel 事件.由于 kernel.terminate
事件没有被触发,你的线轴没有被刷新.因此,您的电子邮件没有被发送.
So let's get to the actual problem. You are in a CLI context, so none of those HttpKernel events will be fired. And since the kernel.terminate
event is not fired, your spool is not being flushed. And thus your emails are not getting sent.
对此有两个很好的解决方案:
There's two good solutions for this:
A) 手动冲洗阀芯.只需执行提供程序在其侦听器中执行的操作即可.在 CLI 命令的末尾添加:
A) Flush the spool manually. Just do what the provider does in its listener. Add this at the end of your CLI command:
if ($app['mailer.initialized']) {
$app['swiftmailer.spooltransport']->getSpool()->flushQueue($app['swiftmailer.transport']);
}
B) 重新配置 mailer
服务以直接使用 ESMTP 传输,而无需通过假脱机:
B) Re-configure the mailer
service to use the ESMTP transport directly without going through the spool:
$app['mailer'] = $app->share(function ($app) {
return new \Swift_Mailer($app['swiftmailer.transport']);
});
两种解决方案都可以.祝你好运!
Either solution should do. Good luck!
这篇关于Silex SwiftMailer 在执行时不建立 SMTP 连接的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!