无法捕获 SwiftMailer 异常?
Can't catch SwiftMailer Exception?
我正在使用 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();
}
不是应该捕获异常吗?
有什么想法吗?
您可以尝试按照 the manual 的建议进行操作:
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.
因此生成的代码可能是:
$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.
}
....
更新:
经过进一步分析,我想我明白了。您可能认为自己没有捕捉到异常,但实际上您捕捉到了。问题是 Swift_TransportException returns 上的 getMessage()
方法完整的堆栈跟踪(至少在我的环境中使用 SwiftMailer 6)...尝试在你的 catch 块中做这样的事情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();
}
经过长时间的挖掘,我同意我得出了与@gere 相同的结论。
令人震惊的是,$ex->getMessage();
附加了一个 stackTrace。
我发现您可以通过注释掉 foreach()
循环来禁用它,该循环将所有这些附加信息添加到 SwiftMailer 核心文件之一的邮件中。如果您决定更新 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);
并注释掉 foreach()
循环甚至只是内部表达式:
$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 上的提交消息所示,here
我正在使用 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();
}
不是应该捕获异常吗?
有什么想法吗?
您可以尝试按照 the manual 的建议进行操作:
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.
因此生成的代码可能是:
$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.
}
....
更新:
经过进一步分析,我想我明白了。您可能认为自己没有捕捉到异常,但实际上您捕捉到了。问题是 Swift_TransportException returns 上的 getMessage()
方法完整的堆栈跟踪(至少在我的环境中使用 SwiftMailer 6)...尝试在你的 catch 块中做这样的事情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();
}
经过长时间的挖掘,我同意我得出了与@gere 相同的结论。
令人震惊的是,$ex->getMessage();
附加了一个 stackTrace。
我发现您可以通过注释掉 foreach()
循环来禁用它,该循环将所有这些附加信息添加到 SwiftMailer 核心文件之一的邮件中。如果您决定更新 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);
并注释掉 foreach()
循环甚至只是内部表达式:
$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 上的提交消息所示,here