如何在 SwiftMailer 中关闭 SMTP 连接
Posted
技术标签:
【中文标题】如何在 SwiftMailer 中关闭 SMTP 连接【英文标题】:How to close Smtp connection in SwiftMailer 【发布时间】:2012-10-26 18:21:29 【问题描述】:我使用 SwiftMailer 从 gearman 工作进程发送电子邮件。我正在使用Swift_SmtpTransport
类发送电子邮件。
问题是,如果这个工作进程保持空闲一段时间,SwiftMailer smtp 连接就会超时。现在,当下一个作业到达时,SwiftMailer 无法发送电子邮件,因为连接已超时。
理想情况下,我希望在每次作业后关闭 smtp 连接。我无法在专门执行此操作的类中找到 api。 unset()
对象也不起作用,因为这是一个静态类。
【问题讨论】:
或许:$transport->stop(), $transport->start() @Dragon Omg 太棒了!我有一个无限循环的后台工作人员,这为我解决了问题。 【参考方案1】:我在一个循环中发送邮件,我正在捕获 Swift_TransportException
并创建一个 Swift_Mailer
的新实例,但这不是正确的解决方法:问题是 transport,而不是邮件程序。解决方案是显式调用Swift_SmtpTransport::stop()
:
foreach($recipients as $to => $body)
try
$message->setTo($to);
$message->setBody(body);
$mailer->send($message);
catch(Swift_TransportException $e)
$mailer->getTransport()->stop();
sleep(10); // Just in case ;-)
这样,Swift 会检测到邮件程序已停止并自动启动,因此它可以从通信错误中正确恢复。
【讨论】:
但是你不应该重试发送吗? @tishma 这个问题询问如何正确重置邮件,这就是我试图回答的问题。 当管道损坏时$mailer->getTransport()->stop()
将失败
@Jekis 请定义“失败”——stop()
method 做了几件事。我的答案中的代码在当时可用的 Swift Mailer 版本中运行良好。
@ÁlvaroGonzález,管道损坏问题主要出现在守护程序脚本中。在 stop 方法内有一个 executeCommand() 和 catch 仅用于 Swift_TransportException。当与服务器的连接断开时,将出现“管道断开”错误。 github.com/swiftmailer/swiftmailer/issues/490【参考方案2】:
有一个粗鲁的选择:明确停止传输。在随后调用 sendMail 方法时,SwiftMailer 将检查传输是否已启动(现在未启动)并再次启动它。 IMNSHO,SwiftMailer 应该拦截 SMTP 超时并自动重新连接。但是,目前,这是解决方法:
function sendMail($your_args)
try
$mailer = Swift_Mailer::newInstance($transport);
$message = Swift_Message::newInstance('Wonderful Subject')
->setFrom(array('john@doe.com' => 'John Doe'))
->setTo(array('receiver@domain.org', 'other@domain.org' => 'A name'))
->setBody('Here is the message itself');
$result = $mailer->send($message);
$mailer->getTransport()->stop();
catch (Swift_TransportException $e)
//this should be caught to understand if the issue is on transport
catch (Exception $e)
//something else happened
【讨论】:
【参考方案3】:当管道损坏时,$mailer->getTransport()->stop() 也会失败。由于这个错误,传输无法停止。解决方法是
// Let's try to send an email.
$tries = 3;
while ($tries--)
try
$sent = $this->mailer->send($message);
break;
catch (\Exception $e)
// Connection problems
// @see https://github.com/swiftmailer/swiftmailer/issues/490
try
// Try to stop
$this->mailer->getTransport()->stop();
catch (\Exception $e)
// Got Exception while stopping transport.
// We have to set _started to 'false' manually, because due to an exception it is 'true' now.
$t = $this->mailer->getTransport();
$reflection = new \ReflectionClass($t);
$prop = $reflection->getProperty('_started');
$prop->setAccessible(true);
$prop->setValue($t, false);
$prop->setAccessible(false);
【讨论】:
【参考方案4】:我正在使用 Swiftmailer 和 AWS SES 在无限循环中运行工作程序,但出现错误:
Expected response code 250 but got code "421", with message "421 Timeout waiting for data from client.
我的脚本的解决方案:
$love = true;
while($love)
$message = Message::to($record->to)
->from(array('no-reply@clouddueling.com' => $user->name()))
->reply(array($user->email => $user->name()))
->subject($record->subject)
->body($body->value)
->html(true)
->send();
if (! $message->was_sent())
throw new Swift_TransportException($errstr . ': ' . $errno);
【讨论】:
这个答案可以使用解释。你的意思是这样的错误没有抛出Swift_TransportException
,而是明确地解决了这个问题?
这是答案还是问题?以上是关于如何在 SwiftMailer 中关闭 SMTP 连接的主要内容,如果未能解决你的问题,请参考以下文章
如何在导航控件片段中关闭导航 DrawerLayout onBackPressed