Search code examples
phpexceptionswiftmailer

Can't catch SwiftMailer Exception?


I'm using SwiftMailer (standalone).

The code below works fine but when I enter an invalid SMTP credentials, an error like this is shown with an entire stack trace:

Failed to authenticate on SMTP server with username "MYUSERNAME" using 3 possible authenticators. Authenticator CRAM-MD5 returned Swift_TransportException: Expected response code 235 but got code "535", with message "535 5.7.0 Invalid login or password
" in /var/www/tester/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/AbstractSmtpTransport.php:457
Stack trace:
#0 /var/www/tester/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/AbstractSmtpTransport.php(341): Swift_Transport_AbstractSmtpTransport->assertResponseCode('535 5.7.0 Inval...', Array)
#1 /var/www/tester/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/EsmtpTransport.php(305): Swift_Transport_AbstractSmtpTransport->executeCommand('NmE0ODlmMWNmOTc...', Array, Array, false, NULL)
#2 /var/www/tester/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/CramMd5Authenticator.php(39): Swift_Transport_EsmtpTransport->executeCommand('NmE0ODlmMWNmOTc...', Array)
#3 /var/www/tester/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/AuthHandler.php(177): Swift_Transport_Esmtp_Auth_CramMd5Authenticator->authenticate(Object(Swift_SmtpTransport), 'MYUSERNAME', 'MYPASSWORD')
#4 /var/www/tester/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/EsmtpTransport.php(371): Swift_Transport_Esmtp_AuthHandler->afterEhlo(Object(Swift_SmtpTransport))
#5 /var/www/tester/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/AbstractSmtpTransport.php(148): Swift_Transport_EsmtpTransport->doHeloCommand()
#6 /var/www/tester/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mailer.php(65): Swift_Transport_AbstractSmtpTransport->start()
#7 /var/www/tester/public/index.php(32): Swift_Mailer->send(Object(Swift_Message))
#8 {main}. Authenticator LOGIN returned Swift_TransportException: Expected response code 250 but got an empty response in /var/www/tester/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/AbstractSmtpTransport.php:445
Stack trace:
#0 /var/www/tester/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/AbstractSmtpTransport.php(341): Swift_Transport_AbstractSmtpTransport->assertResponseCode('', Array)
#1 /var/www/tester/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/EsmtpTransport.php(305): Swift_Transport_AbstractSmtpTransport->executeCommand('RSET\r\n', Array, Array, false, NULL)
#2 /var/www/tester/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/LoginAuthenticator.php(40): Swift_Transport_EsmtpTransport->executeCommand('RSET\r\n', Array)
#3 /var/www/tester/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/AuthHandler.php(177): Swift_Transport_Esmtp_Auth_LoginAuthenticator->authenticate(Object(Swift_SmtpTransport), 'MYUSERNAME', 'MYPASSWORD')
#4 /var/www/tester/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/EsmtpTransport.php(371): Swift_Transport_Esmtp_AuthHandler->afterEhlo(Object(Swift_SmtpTransport))
#5 /var/www/tester/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/AbstractSmtpTransport.php(148): Swift_Transport_EsmtpTransport->doHeloCommand()
#6 /var/www/tester/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mailer.php(65): Swift_Transport_AbstractSmtpTransport->start()
#7 /var/www/tester/public/index.php(32): Swift_Mailer->send(Object(Swift_Message))
#8 {main}. Authenticator PLAIN returned Swift_TransportException: Expected response code 250 but got an empty response in /var/www/tester/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/AbstractSmtpTransport.php:445
Stack trace:
#0 /var/www/tester/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/AbstractSmtpTransport.php(341): Swift_Transport_AbstractSmtpTransport->assertResponseCode('', Array)
#1 /var/www/tester/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/EsmtpTransport.php(305): Swift_Transport_AbstractSmtpTransport->executeCommand('RSET\r\n', Array, Array, false, NULL)
#2 /var/www/tester/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/PlainAuthenticator.php(39): Swift_Transport_EsmtpTransport->executeCommand('RSET\r\n', Array)
#3 /var/www/tester/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/AuthHandler.php(177): Swift_Transport_Esmtp_Auth_PlainAuthenticator->authenticate(Object(Swift_SmtpTransport), 'MYUSERNAME', 'MYPASSWORD')
#4 /var/www/tester/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/EsmtpTransport.php(371): Swift_Transport_Esmtp_AuthHandler->afterEhlo(Object(Swift_SmtpTransport))
#5 /var/www/tester/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/AbstractSmtpTransport.php(148): Swift_Transport_EsmtpTransport->doHeloCommand()
#6 /var/www/tester/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mailer.php(65): Swift_Transport_AbstractSmtpTransport->start()
#7 /var/www/tester/public/index.php(32): Swift_Mailer->send(Object(Swift_Message))
#8 {main}.done

Sample code:

<?php

try {

    $transport = (new Swift_SmtpTransport($host, $port))
        ->setUsername($user)
        ->setPassword($pass);

    $mailer = new \Swift_Mailer($transport);

    $message = (new \Swift_Message('test'))
        ->setFrom(['foo@example.com' => 'bar'])
        ->setTo(['foo@example.com'])
        ->setBody('test');

    $mailer->send($message);

} catch (\Swift_TransportException $ex) {

    echo $ex->getMessage();

} catch (\Exception $ex) {

    echo $ex->getMessage();
}

Isn't it suppose to catch Exceptions?

Any ideas?


Solution

  • You could try to do what the manual suggests:

    If you need to know early whether or not authentication has failed and an Exception is going to be thrown, call the start() method on the created Transport.

    So the resulting code could be:

    $transport = (new Swift_SmtpTransport($host, $port))
        ->setUsername($user)
        ->setPassword($pass); 
    $try {
        $transport->start();
    } catch (\Swift_TransportException $ex) {
        echo $ex->getMessage();
        return; //whatever you want to do.
    }
    ....
    

    UPDATE: After further analysis I think I got it. You may believe that you are not catching the exception, but actually you are. The problem is that the getMessage() method on the Swift_TransportException returns the full stack trace (at least on my env with SwiftMailer 6)... Try do do something like this in your catch block echo "Message start" . $ex->getMessage() . "Message End"; And you should see the texts you added.

    UPDATE 2: If what you want to achieve is to get rid of the stack trace in the message, the only solution I can think of is to subclass the Swift_SmtpTransport, catch the exception earlier and throw a new one with a shorter message. A possibile solution could look like this

    class Better_SwiftSmtpTransport extends  Swift_SmtpTransport
    {
        public function __construct(string $host = 'localhost', int $port = 25, ?string $encryption = null)
        {
            parent::__construct($host, $port, $encryption);
        }
    
        public function start()
        {
            try {
                return parent::start();
            }
            catch (Swift_TransportException $ex) {
                throw new Better_SwiftSmtpTransportException(
                    $ex->getMessage(), 
                    $ex->getCode(), 
                    $ex
                );
            }
        }
    }
    
    class Better_SwiftSmtpTransportException extends Swift_TransportException
    {
        public function __construct(string $message, int $code = 0, Exception $previous = null)
        {
            $message = strtok($message, "\n"); // get only the first line of the message
            parent::__construct($message, $code, $previous);
        }
    }
    
    $transport = (new Better_SwiftSmtpTransport($host, 25))
        ->setUsername($user)
        ->setPassword($password)
    ;
    try {
        $mailer = new \Swift_Mailer($transport);
        $message = (new \Swift_Message('test'))
            ->setFrom(['foo@example.com' => 'bar'])
            ->setTo(['foo@example.com'])
            ->setBody('test');
        $mailer->send($message);
    
    } catch (Swift_TransportException $ex) {
        echo  $ex->getMessage();
    }