How do I get HTML email content before sending in Yii2?
Asked Answered
H

3

11

I want to replace all links in the HTML email with tracker. As far as I know there is this EVENT_BEFORE_SEND event. So I created some behavior that can be used like below

$mailer = \Yii::$app->mailer;
/* @var $mailer \yii\mail\BaseMailer */
$mailer->attachBehavior('archiver', [
   'class' => \app\MailTracker::class
]);

Here's the content of the MyTracker class.

class MailTracker extends Behavior {
    public function events() {
        return [
            \yii\mail\BaseMailer::EVENT_BEFORE_SEND => 'trackMail',
        ];
    }

    /**
     * @param \yii\mail\MailEvent $event
     */
     public function trackMail($event) {
        $message = $event->message;

        $htmlOutput = $this->how_do_i_get_the_html_output();
        $changedOutput = $this->changeLinkWithTracker($htmlOutput);
        $message->getHtmlBody($changedOutput);
     }
}

The problem now is \yii\mail\BaseMailer doesn't provide method to get the HTML output rendered before sending.

How to do this?

UPDATE

The only way I can get this is through this hacky way.

    /* @var $message \yii\swiftmailer\Message */
    if ($message instanceof \yii\swiftmailer\Message) {
        $swiftMessage = $message->getSwiftMessage();
        $r = new \ReflectionObject($swiftMessage);
        $parentClassThatHasBody = $r->getParentClass()
                ->getParentClass()
                ->getParentClass(); //\Swift_Mime_SimpleMimeEntity
        $body = $parentClassThatHasBody->getProperty('_immediateChildren');
        $body->setAccessible(true);
        $children = $body->getValue($swiftMessage);
        foreach ($children as $child) {
            if ($child instanceof \Swift_MimePart &&
                    $child->getContentType() == 'text/html') {
                $html = $child->getBody();
                break;
            }
        }
        print_r($html);
    }
Humfried answered 26/2, 2015 at 3:52 Comment(2)
I've ended up having to do the same thing. Very frustrating.Got
To avoid using Reflection, I've managed to get the mail body (without encoding) by calling $message->getChildren()[0]->getBody()Corrade
C
9

One approach that I've found is to use render() instead of compose(). So we need to render the message string before sending and then compose it again.

$string = Yii::$app->mailer->render('path/to/view', ['params' => 'foo'], 'path/to/layout');

Yii doc: yii\mail\BaseMailer::render()

Constructive answered 6/12, 2015 at 4:5 Comment(0)
K
0

Inorder to edit your email content, you can try editor in view with ckeditor . Ckeditor helps you to edit the contents as you desire.

https://github.com/2amigos/yii2-ckeditor-widget

Edit the contents before sending email.

Kinnard answered 30/3, 2015 at 6:6 Comment(0)
C
0

I created a workaround with preg_match and substitutions, in case is helpful for anyone.

$message = \Yii::$app->mailer->compose('templateName', ['data' => $data])->toString();
// Workaround cause Swift_Mailer doesn't have getBody()
preg_match("/<body>(.*)<\/body>/si", $message, $matches);
$delimitedHtmlBody = $matches[1];
$htmlBody = str_replace("=\r\n", '', $delimitedHtmlBody);
$htmlBody = str_replace("=3D", '=', $htmlBody);
Chaddie answered 21/1, 2022 at 20:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.