如何在 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 连接的主要内容,如果未能解决你的问题,请参考以下文章

如何在线程中关闭 QWebSocket?

如何在导航控件片段中关闭导航 DrawerLayout onBackPressed

如何在 DidSelectRow 中关闭 UIPopover?

如何在 Swift 中关闭 ViewController?

如何在android中关闭AlertDialog

你如何在android studio中关闭版本控制?