代码之家  ›  专栏  ›  技术社区  ›  IMB

无法捕获Swiftmailer异常?

  •  1
  • IMB  · 技术社区  · 6 年前

    我正在使用Swiftmailer(独立)。

    下面的代码工作正常,但是当我输入一个无效的SMTP凭据时,像这样的错误会显示在整个堆栈跟踪中:

    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
    

    样例代码:

    <?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();
    }
    

    它不应该捕获异常吗?

    有什么想法吗?

    2 回复  |  直到 6 年前
        1
  •  1
  •   gere    6 年前

    你可以试着做什么 the manual 建议:

    如果您需要提前知道身份验证是否失败,并且将引发异常,请对创建的传输调用start()方法。

    因此产生的代码可以是:

    $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.
    }
    ....
    

    更新: 经过进一步分析,我想我明白了。你可能认为你没有抓住这个例外,但实际上你是。问题是 getMessage() swift-transportException上的方法返回完整的堆栈跟踪(至少在swiftmailer 6的my env上)…试着在你的接球区做类似的事情 echo "Message start" . $ex->getMessage() . "Message End"; 你应该看到你添加的文本。

    更新2: 如果您想要实现的是去掉消息中的堆栈跟踪,那么我能想到的唯一解决方案是对swift-smtptransport进行子类化,更早地捕获异常,并使用较短的消息抛出一个新的异常。一个可能的解决方案可能看起来像这样

    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();
    }
    
        2
  •  2
  •   PsychoMantis    6 年前

    经过长时间的挖掘,我同意我得出了和@gere相同的结论。

    令人震惊的是, $ex->getMessage(); 附加了StackTrace。

    我发现你可以通过评论来禁用它 foreach() 循环,将所有这些附加信息添加到swiftmail核心文件中的消息中。如果您决定更新Swiftmailer文件,这在将来可能会有问题,但是作为一个临时修复,假设您的文件结构与我的相同,请导航到(对我来说是第187行):

    /vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Authhandler.php

    定位功能 public function afterEhlo(Swift_Transport_SmtpAgent $agent)

    最后,代码如下:

    $message = 'Failed to authenticate on SMTP server with username "' . $this->username . '" using ' . $count . ' possible authenticators.';
    foreach ($errors as $error) {
        $message .= ' Authenticator ' . $error[0] . ' returned ' . $error[1] . '.';
    }
    
    throw new Swift_TransportException($message);
    

    并对 前额() 循环,甚至只是内部表达式:

    $message = 'Failed to authenticate on SMTP server with username "' . $this->username . '" using ' . $count . ' possible authenticators.';
    /*foreach ($errors as $error) {
        $message .= ' Authenticator ' . $error[0] . ' returned ' . $error[1] . '.';
    }*/
    
    throw new Swift_TransportException($message);
    

    编辑:我忘了提一下,这段代码迭代验证尝试中使用的每个验证器,并以堆栈跟踪的形式吐出它们遇到的错误,这是您看到的附加数据。只是为了澄清。

    编辑2:这是24天前通过替换第182行修复的:

    $errors[] = [$authenticator->getAuthKeyword(), $e];

    用:

    $errors[] = [$authenticator->getAuthKeyword(), $e->getMessage()];

    如git上的commit消息所示, here

    推荐文章