To debug email sending in Yii2 you have the useFileTransfer option, enabled by default, on the component configuration. With this option you can control whether mail is delivered to a MTA (Mail Transport Agent) or instead written to file.
It’s a convenient way for developers to check the content of an email, or to do tests: mails are written to @runtime/mail as .eml files which can be opened with a text editor or an email client.
But it doesn’t fit the situation where you want your customer to testdrive the application, maybe with real email addresses but of course you don’t want these emails to be delivered to the real email address? I wanted a solution which allowed me to collect all the emails generated from the application to a single email address.
The first idea was to implement a custom mail interface, but that would be too much hassle for such a small task. Also, doing a small Mailer component into the app, inheriting from the base mailer, could have worked. In the end I had chosen the event approach.
The BaseMailer class has a beforeSend() event. Let’s exploit it.
Based on Usuario suggestions, let’s create a config/events.php file with the following content:
<?php
use yii\base\Event;
use yii\swiftmailer\Mailer;
/**
* Override mail recipients
*/
Event::on(Mailer::class, Mailer::EVENT_BEFORE_SEND, function ($e) {
$msg = $e->message;
$original['to'] = $msg->getTo();
$original['cc'] = $msg->getCc();
$original['bcc'] = $msg->getBcc();
$original_txt = "Original recipients: ";
foreach ($original as $k => $o) {
if (empty($o)) {
continue;
}
if (is_array($o)) {
$o = implode(",", array_keys($o));
}
$original_txt .= "{$k}: {$o} ";
}
$msg->to = "your@email.it";
$msg->setCc(null);
$msg->setBcc(null);
$msg->attachContent($original_txt, ['contentType' => 'text/plain', 'fileName' => 'original_recipients.txt']);
});
Now let’s make this load. Add to web/index.php:
require(__DIR__ . '/../config/events.php');
Now just configure the SMTP transport, and you’re done! All mails generated from your Yii app will end up to the single recipient stated in the bottom of the events.php file!
Very useful!
But it’s important to clear CC and BCC too, so it avoids sending messages by mistake:
$msg->setCc(null);
$msg->setBcc(null);
Right, thanks! I’ll update
Check out the fileTransportCallback property… you can do your logic there, remove the fileTransport, send, set the fileTransport again an return the name of the log file. The you get both, log file on @runtime/mail and the email sent