Logging swiftmailer envía actividad () en symfony2

Estoy usando swiftmailer para enviar correos desde mi proyecto symfony2.2. ¿Hay alguna manera de registrar globalmente toda la información del correo electrónico y enviar resultados?

Sería genial si el método de envío de correo () tiene un evento de activación, pero no puedo verlo.

Servicio:

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

Config:

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

Esta pregunta ya fue respondida. Esta solución es mejor para Symfony 3 combinado con Monolog. Se basa en umpirsky su Respuesta. Pero sin la sobrecarga de un registrador de archivos personalizado.

Nota: los registros se colocarán en ./var/logs / …

AppBundle \ Util \ MailerLoggerUtil.php

 logger = $logger; } /** * @param Swift_Events_SendEvent $evt */ public function beforeSendPerformed(Swift_Events_SendEvent $evt) { // ... } /** * @param Swift_Events_SendEvent $evt */ public function sendPerformed(Swift_Events_SendEvent $evt) { $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.yml

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

Si desea que los registros de correo estén en otro canal, agregue esto:

config.yml (opcional)

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

Lo hice de esta manera:

1. Mi configuración de servicio

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

2. Servicio de envolvente de correo

Extiende Swift_Mailer , ya que se pasa a diferentes clases esperando que el correo sea una instancia de Swift_Mailer . Y crea la instancia de Swift_Mailer como un campo, porque … $transport es private en \Swith_Mailer ( enlace ). El código sería mucho mejor si $transport estuviera 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. Constructor de paquetes

 // /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. Y la clase 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 - ie event_dispatcher */ } } 

Puede ajustar SwiftMailer con su propia clase de correo personalizado. Me gusta,

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

Al agregar lo siguiente a la sección ‘servicios’ de su configuración, se imprimirá la interacción con el transporte a stdout (que puede ser útil si está depurando mediante los comandos de la consola, por ejemplo, ‘swiftmailer: email: send’ o ‘swiftmailer: spool: enviar’):

 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] 

Ejemplo de salida, usando transporte SMTP a localhost:

 $ 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:  << 250 OK >> RCPT TO:  << 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