如何在SwiftMailer中关闭Smtp连接

16
我使用SwiftMailer从gearman工作进程发送电子邮件。 我正在使用Swift_SmtpTransport类发送电子邮件。
问题在于,如果这个工作进程空闲了一段时间,SwiftMailer smtp连接就会超时。 现在,当下一个任务到达时,因为连接已超时,SwiftMailer无法发送电子邮件。
理想情况下,我希望在每个任务之后关闭smtp连接。 我无法找到类中专门执行此操作的api。unset()对象也不起作用,因为这是静态类。

2
也许是:$transport->stop(),$ transport->start() - user557846
@Dragon 天哪,非常感谢!我有一个在无限循环中的后台工作器,这个解决了我的问题。 - Michael J. Calkins
4个回答

11

有个粗暴的选项:显式地停止传输。在调用方法 sendMail 的后续调用中,SwiftMailer 将检查传输是否已启动(现在没有),然后重新启动它。 在我看来,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  
    }

}

11

我在循环中发送邮件,当捕获到 Swift_TransportException 时创建了一个 Swift_Mailer 的新实例,但这并不是正确的解决方法:问题出在 传输方式 而不是 邮件发送器。解决方法是显式调用 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检测到邮件发送程序已经停止,并自动启动它,因此可以正确地从通信错误中恢复。


1
但是你不应该重试发送吗? - tishma
@tishma 这个问题是关于如何正确重置邮件程序,这就是我尝试回答的。 - Álvaro González
当管道断裂时,$mailer->getTransport()->stop() 将失败。 - Jekis
@Jekis 请定义“失败”——stop()方法会执行多个操作。我回答中的代码在当时可用的Swift Mailer版本中一直运行良好。 - Álvaro González
@ÁlvaroGonzález,破管问题主要出现在守护进程脚本中。在stop方法内部有一个executeCommand()和仅捕获Swift_TransportException的catch。当与服务器的连接断开时,将会出现“破管”错误。https://github.com/swiftmailer/swiftmailer/issues/490 - Jekis

1
当管道破裂时,$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);
        }
    }
}

0

我正在使用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);
}

3
这个回答可能需要解释一下。你的意思是,这种错误没有抛出 Swift_TransportException,但明确地这样做可以解决问题吗? - Álvaro González
4
这是一个回答还是一个问题? - caponica

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接