CakePHP 4自定义邮件传输中获取自定义变量(Postmark批量邮件)
解决Postmark批量邮件个性化内容的问题
方法1:在Mailer中预渲染每个收件人的邮件内容
既然自定义Transport无法直接访问NewsletterMailer里的ViewVars,你可以提前在Mailer层为每个订阅者生成渲染好的个性化HTML内容,再传递给Transport处理批量发送。
修改NewsletterMailer.php
// NewsletterMailer.php $viewBuilder = $this->viewBuilder() ->setTemplate('newsletter_mail') ->setLayout('default'); // 遍历订阅者,生成每封邮件的个性化内容 $batchEmails = []; foreach ($subscribers->all() as $subscriber) { // 为当前订阅者设置专属ViewVars $viewBuilder->setVars([ 'company' => $company, 'subscriber' => $subscriber // 订阅者信息用于个性化展示 ]); // 渲染HTML内容 $htmlContent = $this->getView()->render($viewBuilder); $batchEmails[] = [ 'To' => $subscriber->email, 'From' => "{$newsletter->sender} <{$company->companyname}>", 'Subject' => $newsletter->name, 'HtmlBody' => $htmlContent ]; } // 将预生成的邮件数组传递给Transport return $this ->setEmailFormat('html') ->setProfile('newsletter') ->set(['batch_emails' => $batchEmails]);
修改NewslettersTransport.php
在Transport的send()方法中直接获取预生成的邮件数据,按Postmark要求拆分批量发送:
// NewslettersTransport.php public function send(Email $email) { $batchEmails = $email->get('batch_emails'); // 按每500封一组拆分 $batches = array_chunk($batchEmails, 500); foreach ($batches as $batch) { // 调用Postmark Batch API发送 $this->postmarkClient->sendEmailBatch($batch); } return true; }
方法2:让Transport直接访问View配置与ViewVars
如果希望在Transport中动态渲染内容,可以通过Email对象传递ViewBuilder和基础ViewVars,在Transport层完成个性化渲染。
修改NewsletterMailer.php
// NewsletterMailer.php $viewBuilder = $this->viewBuilder() ->setTemplate('newsletter_mail') ->setLayout('default') ->setVars([ 'company' => $company ]); return $this ->setEmailFormat('html') ->setTo($subscribers->all()->toArray()) ->setFrom([$newsletter->sender => $company->companyname]) ->setSubject($newsletter->name) ->setProfile('newsletter') ->set([ 'view_builder' => $viewBuilder, 'base_view_vars' => $viewBuilder->getVars() ]);
修改NewslettersTransport.php
初始化View实例,为每个收件人合并ViewVars并渲染:
// NewslettersTransport.php use Cake\View\View; use Cake\ORM\TableRegistry; public function send(Email $email) { $viewBuilder = $email->get('view_builder'); $baseVars = $email->get('base_view_vars'); $toRecipients = $email->getTo(); $from = $email->getFrom(); $subject = $email->getSubject(); $batchEmails = []; foreach ($toRecipients as $emailAddress => $name) { // 根据邮箱获取订阅者信息(需自行实现查询逻辑) $subscriberTable = TableRegistry::getTableLocator()->get('Subscribers'); $subscriber = $subscriberTable->findByEmail($emailAddress)->first(); // 合并基础变量与订阅者专属变量 $viewBuilder->setVars(array_merge($baseVars, [ 'subscriber' => $subscriber ])); // 初始化View并渲染内容 $view = new View(); $htmlContent = $view->render($viewBuilder); $batchEmails[] = [ 'To' => $emailAddress, 'From' => key($from) . ' <' . current($from) . '>', 'Subject' => $subject, 'HtmlBody' => $htmlContent ]; } // 拆分批量并发送 $batches = array_chunk($batchEmails, 500); foreach ($batches as $batch) { $this->postmarkClient->sendEmailBatch($batch); } return true; }
方法3:利用Postmark官方模板功能
如果你的Postmark账户已创建模板,可以直接传递模板变量,让Postmark平台帮你完成个性化渲染,省去本地视图处理步骤。
修改NewsletterMailer.php
// NewsletterMailer.php return $this ->setTo($subscribers->all()->toArray()) ->setFrom([$newsletter->sender => $company->companyname]) ->setSubject($newsletter->name) ->setProfile('newsletter') ->set([ 'postmark_template_id' => '你的Postmark模板ID', 'base_template_vars' => [ 'company_name' => $company->companyname // 其他基础模板变量 ] ]);
修改NewslettersTransport.php
// NewslettersTransport.php use Cake\ORM\TableRegistry; public function send(Email $email) { $templateId = $email->get('postmark_template_id'); $baseVars = $email->get('base_template_vars'); $toRecipients = $email->getTo(); $from = $email->getFrom(); $batchEmails = []; foreach ($toRecipients as $emailAddress => $name) { $subscriberTable = TableRegistry::getTableLocator()->get('Subscribers'); $subscriber = $subscriberTable->findByEmail($emailAddress)->first(); $batchEmails[] = [ 'To' => $emailAddress, 'From' => key($from) . ' <' . current($from) . '>', 'TemplateId' => $templateId, 'TemplateModel' => array_merge($baseVars, [ 'subscriber_name' => $subscriber->name // 其他订阅者专属模板变量 ]) ]; } $batches = array_chunk($batchEmails, 500); foreach ($batches as $batch) { $this->postmarkClient->sendEmailBatch($batch); } return true; }
内容的提问来源于stack exchange,提问作者DvL
相关产品推荐
相关产品推荐

