php - 当邮件发送失败时,SwiftMailer 会默默地忽略错误

标签 php email symfony smtp swiftmailer

当从内部 Controller 运行并且通过 spool: { type: memory } 配置内存中假脱机时,swiftmailer 似乎是这样工作的:

  • 每当在 Controller 内调用 mailer->send($message) 时 -> 将消息保存在内存中
  • 当 Controller 完成工作并且 symfony 内核即将关闭时(在事件 kernel.terminate 或 smth 中) - 检查内存中保存的消息并_实际将其提交到 SMTP 服务器

然而,最后一步似乎默默地忽略了在将邮件提交到 SMTP 服务器时可能引发的任何错误。

我发现当我从 Amazon SES 设置 SMTP 时,错误被悄悄吞没,并且进行了错误的配置:

mailer_transport: smtp
# For illustration I put WRONG port 9999, which means that this should trigger
# error (correct port would be 587)
mailer_port: 9999
mailer_encryption: tls
mailer_host: email-smtp.us-east-1.amazonaws.com
mailer_user: SES_USER_KEY
mailer_password: SES_USER_SECRET 

现在,如果我尝试从 symfony 命令使用错误的配置发送电子邮件,正如预期的那样,我会得到 Swift_TransportException 并且错误不会被默默地忽略。 (根据我的观察,symfony 命令似乎不使用内存假脱机并尝试立即发送消息)

下面是命令示例(因此您确定我做得正确)。

protected function execute(InputInterface $input, OutputInterface $output) {
     $email = $input->getArgument('email');
     $content = $this->getHelper('dialog')->ask($output, 'Please input content:');

     $emsg = \Swift_Message::newInstance();
     $emsg->setTo($email);
     $emsg->setFrom('<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="8febcfe2f6a2fceafca2f9eafde6e9e6eaeba2ebe0e2eee6e1a1ece0e2" rel="noreferrer noopener nofollow">[email protected]</a>');
     $emsg->setSubject('This is subject');
     $emsg->setBody($content);

     $this->getContainer()->get('mailer')->send($emsg);
}

这是抛出异常 Swift_TransportException 时的命令输出:

ubuntu@localhost:~/my-app$ console acme:email:send <a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="72170a1b01061b1c1532171f131b1e5c111d1f" rel="noreferrer noopener nofollow">[email protected]</a>
We are going to send email to :<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="d1b4a9b8a2a5b8bfb691b4bcb0b8bdffb2bebc" rel="noreferrer noopener nofollow">[email protected]</a>

Please input content:asdf adf


[Swift_TransportException]                                                                                    
Connection could not be established with host email-smtp.us-east-1.amazonaws.com [Connection timed out #110]  

但是,如果我尝试从 Controller 发送电子邮件,则不会看到任何错误消息。基本上这意味着,如果出现错误(配置错误或网络错误或 SMTP 服务器关闭),我发送的所有电子邮件都会默默消失,没有任何痕迹(不会引发异常,不会在 dev.log 中记录任何错误)都不在 prod.log 中)。

如何强制 Swiftmailer 留下失败的投递尝试的痕迹?

最佳答案

您可以通过手动刷新后台处理程序来强制发送电子邮件,这样您就可以捕获异常并根据需要进行记录。我在此处的文档中找到了一个示例(针对 Controller 的上下文进行了修改)...

https://symfony.com/doc/2.6/cookbook/console/sending_emails.html

$message = new \Swift_Message();

// ... prepare the message

$mailer = $this->get('mailer');

$mailer->send($message);

// now manually flush the queue
$spool = $mailer->getTransport()->getSpool();
$transport = $this->get('swiftmailer.transport.real');

$spool->flushQueue($transport);

虽然该示例最初是在控制台环境中使用的,但我认为它没有理由在 Controller 中无效。

编辑:

记录异常的另一种方法是利用 Swiftmailer 事件系统。这涉及创建一个实现 \Swift_Events_TransportExceptionListener 的自定义插件(作为服务最好) ,然后用邮件程序注册它。

例如自定义插件类:

namespace Acme\DemoBundle\SwiftPlugin;

use Symfony\Bridge\Monolog\Logger;

class SwiftExceptionLoggerPlugin implements \Swift_Events_TransportExceptionListener
{
    private $logger;

    public function __construct(Logger $logger)
    {
        $this->logger = $logger;
    }

    /**
     * Invoked as a TransportException is thrown in the Transport system.
     *
     * @param Swift_Events_TransportExceptionEvent $evt
     */
    public function exceptionThrown(\Swift_Events_TransportExceptionEvent $evt)
    {
        $e = $evt->getException();
        $message = $e->getMessage();
        $this->logger->err(sprintf("Swiftmailer Exception: %s", $message));
    }
}

然后将其与 swiftmailer.default.plugin 一起添加为服务标签。这将自动将其注册为 Swiftmailer 插件...

<service id="acme.demo.swift_plugin.swift_exception_logger_plugin" class="Acme\DemoBundle\SwiftPlugin\SwiftExceptionLoggerPlugin">
    <tag name="swiftmailer.default.plugin" />
    <argument type="service" id="logger" />
</service>

这将在 dev/prod 的标准日志区域中记录异常消息。但是,如果超时需要很长时间才能发生,我认为如果用户单击或关闭浏览器/选项卡等,它仍然可能无法正确记录。也许上述内容以及通过 mailer_timeout 为 Swiftmailer 设置较低的超时值参数。

关于php - 当邮件发送失败时,SwiftMailer 会默默地忽略错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27082631/

相关文章:

php - 从 codeigniter 中删除查询

php - 使用 mailgun PHP API 发送电子邮件

java - 将电子邮件发送到以下服务器失败(apache commons - Java)

php - 使用 OptionsResolver 组件进行高级类型验证

php - Symfony2 phpunit 测试认证

php - Behat Mink 文件上传在提交时未找到文件

php - 根据php中的选择框值更新表格

magento - 如何在Magento中将产品缩略图添加到订单查看页面?

email - 将 Google Plus(一个或共享)链接添加到电子邮件简报

hosting - 间歇性完全渲染失败最终无法连接 - City_Magazine Theme