我使用 swiftmailer 从我的 symfony2.2 项目中发送邮件。有没有办法在全球范围内记录所有电子邮件信息并发送结果?
如果 mailer send() 方法触发了某些事件,那就太好了,但我看不到它确实如此。
我使用 swiftmailer 从我的 symfony2.2 项目中发送邮件。有没有办法在全球范围内记录所有电子邮件信息并发送结果?
如果 mailer send() 方法触发了某些事件,那就太好了,但我看不到它确实如此。
这个问题已经回答了,这个解决方案更适合 Symfony 4 和 Monolog。它基于 umpirsky 他的回答。但没有自定义文件记录器的开销。
注意:日志将放在 ./var/logs/...
应用\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;
}
}
}
服务.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]
服务:
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 }
我是这样做的:
# /src/Tiriana/MyBundle/Resources/config/services.yml
parameters:
swiftmailer.class: Tiriana\MyBundle\Util\MailerWrapper
它扩展Swift_Mailer
了,因为它被传递给期望 mailer 成为实例的不同类Swift_Mailer
。并将实例创建Swift_Mailer
为字段,因为...$transport
在(链接)中private
。如果是... ,代码会好得多\Swith_Mailer
$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);
}
}
// /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
}
}
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 */
}
}
将以下内容添加到配置的“服务”部分将打印与传输到标准输出的交互(如果您使用控制台命令进行调试,这可能很有用,例如 'swiftmailer:email:send' 或 'swiftmailer:spool:发送'):
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 传输到 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: <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
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
}
}