How to close Smtp connection in SwiftMailer

13,852

Solution 1

There is a rude option: stop the transport explicitly. On subsequent calls of the method sendMail, SwiftMailer will check whether the transport is up (it is not, now) and start it again. IMNSHO, SwiftMailer should intercept the SMTP timeout and reconnect automatically.But, for now, this is the workaround:

function sendMail($your_args) {
    try{ 
      $mailer = Swift_Mailer::newInstance($transport);
      $message = Swift_Message::newInstance('Wonderful Subject')
        ->setFrom(array('[email protected]' => 'John Doe'))
        ->setTo(array('[email protected]', '[email protected]' => '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  
    }

}

Solution 2

I send mails in a loop and I was catching the Swift_TransportException and creating a new instance of Swift_Mailer but it wasn't the right fix: the problem is the transport, not the mailer. The solution is to issue an explicit call to 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 ;-)
    }
}

This way, Swift detects the mailer is stopped and starts it automatically, so it recovers correctly from communication errors.

Solution 3

When pipe is broken $mailer->getTransport()->stop() will fail as well. And due to this error transport cannot be stopped. The workaround is

// 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);
        }
    }
}
Share:
13,852
Nands
Author by

Nands

Updated on June 13, 2022

Comments

  • Nands
    Nands almost 2 years

    I use SwiftMailer to send emails from a gearman worker process. I'm using the Swift_SmtpTransport class to send emails.

    The problem is that if this worker process stays idle for sometime, the SwiftMailer smtp connection times out. Now when the next job arrives, SwiftMailer fails to send emails as the connection has been timed out.

    Ideally, I would want to close the smtp connection after every job. I'm unable to locate a api in the class which does this specifically. Neither does unset() object works since this is a static class.

  • Álvaro González
    Álvaro González about 10 years
    This answer could use an explantion. Do you mean that such error was not throwing Swift_TransportException, but doing it explicitly fixes the issue?
  • caponica
    caponica about 10 years
    Is this an answer or a question?
  • tishma
    tishma almost 10 years
    But shouldn't you retry sending?
  • Álvaro González
    Álvaro González almost 10 years
    @tishma The question asks how to properly reset the mailer and that's what I try to answer.
  • Jekis
    Jekis over 7 years
    When pipe is broken $mailer->getTransport()->stop() will fail
  • Álvaro González
    Álvaro González over 7 years
    @Jekis Please define "fail"—the stop() method does several things. The code in my answer has been working fine for the Swift Mailer version available at the time.
  • Jekis
    Jekis over 7 years
    @ÁlvaroGonzález, broken pipe issue appears in daemon scripts mostly. Inside the stop method there is an executeCommand() and catch for Swift_TransportException only. When connection with the server is broken there will be a "broken pipe" error. github.com/swiftmailer/swiftmailer/issues/490