【问题标题】:Logging swiftmailer send() activity in symfony2在 symfony2 中记录 swiftmailer send() 活动
【发布时间】:2013-08-03 13:12:02
【问题描述】:

我正在使用 swiftmailer 从我的 symfony2.2 项目中发送邮件。有没有办法在全球范围内记录所有电子邮件信息并发送结果?

如果 mailer send() 方法有触发 somę 事件,那就太好了,但我看不到。

【问题讨论】:

    标签: php symfony logging swiftmailer symfony-2.2


    【解决方案1】:

    这个问题已经回答过了,这个解决方案更适合 Symfony 4 和 Monolog。它基于 umpirsky 他的回答。但没有自定义文件记录器的开销。

    注意:日志会放在 ./var/logs/...

    App\Util\MailLoggerUtil.php

    <?php
    
    namespace App\Util;
    
    use Psr\Log\LoggerInterface;
    use Psr\Log\LogLevel;
    use Swift_Events_SendEvent;
    use Swift_Events_SendListener;
    
    class MailerLoggerUtil implements Swift_Events_SendListener
    {
        protected $logger;
    
        /**
         * MailerLoggerUtil constructor.
         *
         * @param LoggerInterface $logger
         */
        public function __construct(LoggerInterface $logger)
        {
            $this->logger = $logger;
        }
    
        /**
         * @param Swift_Events_SendEvent $evt
         */
        public function beforeSendPerformed(Swift_Events_SendEvent $evt)
        : void
        {
            // ...
        }
    
        /**
         * @param Swift_Events_SendEvent $evt
         */
        public function sendPerformed(Swift_Events_SendEvent $evt)
        : void
        {
            $level   = $this->getLogLevel($evt);
            $message = $evt->getMessage();
    
            $this->logger->log(
                $level,
                $message->getSubject().' - '.$message->getId(),
                [
                    'result'  => $evt->getResult(),
                    'subject' => $message->getSubject(),
                    'to'      => $message->getTo(),
                    'cc'      => $message->getCc(),
                    'bcc'     => $message->getBcc(),
                ]
            );
        }
    
        /**
         * @param Swift_Events_SendEvent $evt
         *
         * @return string
         */
        private function getLogLevel(Swift_Events_SendEvent $evt)
        : string
        {
            switch ($evt->getResult()) {
                // Sending has yet to occur
                case Swift_Events_SendEvent::RESULT_PENDING:
                    return LogLevel::DEBUG;
    
                // Email is spooled, ready to be sent
                case Swift_Events_SendEvent::RESULT_SPOOLED:
                    return LogLevel::DEBUG;
    
                // Sending failed
                default:
                case Swift_Events_SendEvent::RESULT_FAILED:
                    return LogLevel::CRITICAL;
    
                // Sending worked, but there were some failures
                case Swift_Events_SendEvent::RESULT_TENTATIVE:
                    return LogLevel::ERROR;
    
                // Sending was successful
                case Swift_Events_SendEvent::RESULT_SUCCESS:
                    return LogLevel::INFO;
            }
        }
    }
    

    services.yaml

    App\Util\MailLoggerUtil:
        arguments: ["@logger"]
        tags:
          - { name: monolog.logger, channel: mailer }
          - { name: "swiftmailer.default.plugin" }
    

    如果您希望邮件日志位于另一个频道中,请添加:

    dev/monolog.yaml(可选)

    monolog:
        handlers:
            mailer:
                level:    debug
                type:     stream
                path:     '%kernel.logs_dir%/mailer.%kernel.environment%.log'
                channels: [mailer]
    

    【讨论】:

    • 非常感谢 - 这真的很有帮助!
    • 很好的答案! Symfony 3 也能正常工作
    【解决方案2】:

    服务:

    class MessageFileLogger implements Swift_Events_SendListener
    {
        private $filename;
    
        public function __construct($filename)
        {
            $this->filename = $filename;
        }
    
        public function getMessages()
        {
            return $this->read();
        }
    
        public function clear()
        {
            $this->write(array());
        }
    
        public function beforeSendPerformed(Swift_Events_SendEvent $evt)
        {
            $messages = $this->read();
            $messages[] = clone $evt->getMessage();
    
            $this->write($messages);
        }
    
        public function sendPerformed(Swift_Events_SendEvent $evt)
        {
        }
    
        private function read()
        {
            if (!file_exists($this->filename)) {
                return array();
            }
    
            return (array) unserialize(file_get_contents($this->filename));
        }
    
        private function write(array $messages)
        {
            file_put_contents($this->filename, serialize($messages));
        }
    }
    

    配置:

    services:
        umpirsky.mailer.message_file_logger:
            class: MessageFileLogger
            arguments:
                - %kernel.logs_dir%/mailer.log
            tags:
                - { name: swiftmailer.plugin }
    

    【讨论】:

    • 这应该是要走的路。
    【解决方案3】:

    我是这样做的:

    1。我的服务配置

    # /src/Tiriana/MyBundle/Resources/config/services.yml
    parameters:
         swiftmailer.class:  Tiriana\MyBundle\Util\MailerWrapper
    

    2。邮件包装服务

    它扩展了Swift_Mailer,因为它被传递给不同的类,期望邮件程序是Swift_Mailer 的实例。 它创建Swift_Mailer 实例作为字段,因为... $transport 在\Swith_Mailer (link) 中是private。如果$transport 是protected,代码会好很多...

    // /src/Tiriana/MyBundle/Util/MailerWrapper.php
    namespace Tiriana\MyBundle\Util;
    
    use Monolog\Logger;
    use Monolog\Handler\StreamHandler;
    
    class MailerWrapper extends \Swift_Mailer
    {
        private $_logger;
    
        /** @var \Swift_Mailer */
        private $_mailer;
    
        public function send(\Swift_Mime_Message $message, &$failedRecipients = null)
        {
            $this->_log('BEFORE SEND');  // <-- add your logic here
            $ret = $this->_mailer->send($message, $failedRecipients);
            $this->_log('AFTER SEND');  // <-- add your logic here
    
            return $ret;
        }
    
        /** @return Logger */
        public function getLogger()
        {
            return $this->_logger;
        }
    
        protected function _log($msg)
        {
            $this->getLogger()->debug(__CLASS__ . ": " . $msg);
        }
    
        public function __construct(\Swift_Transport $transport, Logger $logger)
        {
            /* we need _mailer because _transport is private
               (not protected) in Swift_Mailer, unfortunately... */
            $this->_mailer = parent::newInstance($transport);
            $this->_logger = $logger;
        }
    
        public static function newInstance(\Swift_Transport $transport)
        {
            return new self($transport);
        }
    
        public function getTransport()
        {
            return $this->_mailer->getTransport();
        }
    
        public function registerPlugin(Swift_Events_EventListener $plugin)
        {
            $this->getTransport()->registerPlugin($plugin);
        }
    }
    

    3。捆绑构建器

    // /src/Tiriana/MyBundle/TirianaMyBundle.php
    namespace Tiriana\MyBundle;
    
    use Symfony\Component\HttpKernel\Bundle\Bundle;
    use Symfony\Component\DependencyInjection\ContainerBuilder;
    
    use Tiriana\MyBundle\DependencyInjection\Compiler\OverrideServiceSwiftMailer;
    
    class TirianaMyBundle extends Bundle
    {
        public function build(ContainerBuilder $container)
        {
            parent::build($container);
            $container->addCompilerPass(new OverrideServiceSwiftMailer());  // <-- ADD THIS LINE
        }
    }
    

    4。还有OverrideServiceSwiftMailer类

    // /src/Tiriana/MyBundle/DependencyInjection/Compiler/OverrideServiceSwiftMailer.php
    namespace Tiriana\MyBundle\DependencyInjection\Compiler;
    use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
    use Symfony\Component\DependencyInjection\ContainerBuilder;
    use Symfony\Component\DependencyInjection\Reference;
    
    class OverrideServiceSwiftMailer implements CompilerPassInterface
    {
        public function process(ContainerBuilder $container)
        {
            /* @var $definition \Symfony\Component\DependencyInjection\DefinitionDecorator */
            $definition = $container->findDefinition('mailer');
            $definition->addArgument(new Reference('logger'));
            /* add more dependencies if you need - i.e. event_dispatcher */
        }
    }
    

    【讨论】:

      【解决方案4】:

      将以下内容添加到配置的“服务”部分将打印与传输到标准输出的交互(如果您使用控制台命令进行调试,这可能很有用,例如“swiftmailer:email:send”或“swiftmailer” :spool:send'):

      services:
      
          # (...)
      
          swiftmailer.plugins.loggerplugin:
              class: 'Swift_Plugins_LoggerPlugin'
              arguments: ['@swiftmailer.plugins.loggerplugin.logger']
              tags: [{ name: 'swiftmailer.default.plugin' }]
      
          swiftmailer.plugins.loggerplugin.logger:
              class: 'Swift_Plugins_Loggers_EchoLogger'
              arguments: [false]
      

      示例输出,使用 SMTP 传输到本地主机:

      $ app/console swiftmailer:email:send --subject="Test" --body="Yo! :)" --from="user@example.com" --to="user@example.com"
      
      ++ Starting Swift_Transport_EsmtpTransport
      << 220 example.com ESMTP Exim 4.86 Thu, 07 Jan 2016 13:57:43 +0000
      
      >> EHLO [127.0.0.1]
      
      << 250-example.com Hello localhost [127.0.0.1]
      250-SIZE 52428800
      250-8BITMIME
      250-PIPELINING
      250-AUTH PLAIN LOGIN
      250-STARTTLS
      250 HELP
      
      ++ Swift_Transport_EsmtpTransport started
      >> MAIL FROM: <user@example.com>
      
      << 250 OK
      
      >> RCPT TO: <user@example.com>
      
      << 451 Temporary local problem - please try later
      
      !! Expected response code 250/251/252 but got code "451", with message "451 Temporary local problem - please try later"
      >> RSET
      
      << 250 Reset OK
      
      Sent 0 emails
      
      ++ Stopping Swift_Transport_EsmtpTransport
      >> QUIT
      
      << 221 example.com closing connection
      
      ++ Swift_Transport_EsmtpTransport stopped
      

      【讨论】:

      • 缺少一件小事 - 如果您有超过 1 个邮件程序(或非默认邮件程序名称)tags: [{ name: 'swiftmailer.%mailer_name%.plugin' }]。另外你应该在邮件配置中添加logging: true
      【解决方案5】:

      你可以用你自己的自定义邮件类包裹SwiftMailer。喜欢,

      class MyMailer
      {
          /**
           * @var \Swift_Mailer
           */
          private $mailer;
      
          /**
           * Mail the specified mailable using swift mailer.
           * 
           * @param SwiftMessage $swiftMessage
           */
          public function mail(\SwiftMessage $swiftMessage)
          {
              // PRESEND ACTIONS
      
              $sent = $this->mailer->send($swiftMessage);
      
              // POST SEND ACTIONS
          }
      }
      

      【讨论】:

      • 感谢重播。没关系,但这需要我更改代码中的所有邮件程序 -> send() 调用。这是我想避免的。如果我可以覆盖邮件服务,并且...将先前定义的邮件服务传递给它,那将是理想的:) - 我目前正在尝试找到定义“邮件”服务的地方,所以我现在是什么参数和它收到的 args ,但我似乎找不到它......
      猜你喜欢
      • 1970-01-01
      • 2011-09-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多