使用Swiftmailer,我可以替换或删除消息部分吗?


With Swiftmailer, can I replace or remove a message part?

我正在使用Swift Mailer将邮件发送到相当大的电子邮件地址列表。邮件会针对每个收件人进行轻微自定义。某些占位符将替换为唯一文本。

我认为多次重用一个Swift_Message实例会更有效(更少的垃圾收集等)。我只是setTo()setBody()并再次发送到下一个地址。

这适用于单个部分主体,通常只是 html。但。。。当我想要第二部分时,通常是文本,我可以做addPart(),但下次循环时,这将添加另一部分,然后是另一部分等...... setBody不会出现问题,因为这会覆盖现有正文。

有没有办法覆盖或删除现有零件?

谢谢

为了扩展亨德里克和阿拉斯代尔的答案,我建议考虑使用装饰器插件。http://swiftmailer.org/docs/plugins.html#using-the-decorator-plugin

该插件不会操作单个消息部分,而是为每个收件人替换整个消息的所需占位符。

例如

$message = 'Swift_Message::newInstance();
$replacements = array();
foreach ($users as $user) {
    $replacements[$user['email']] = array(
        '{username}' => $user['username'],
        '{password}' => $user['password']
    );
    $message->addTo($user['email']);
}
$decorator = new 'Swift_Plugins_DecoratorPlugin($replacements);
$mailer->registerPlugin($decorator);
$message
    ->setSubject('Important notice for {username}')
    ->setBody(
        "Hello {username}, we have reset your password to {password}'n" .
        "Please log in and change it at your earliest convenience."
    );
$message->addPart('{username} has been reset with the password: {password}', 'text/plain');
//..
$mailer->send($message);

此外,在 PHP 中,对象是通过引用传递的,因此您可以直接操作各个部件主体或内容类型。

$textPart = 'Swift_MimePart::newInstance('Hello World', 'text/plain');
$htmlPart = clone $textPart;
$htmlPart->setContentType('text/html');
$message->setTo('someone@example.com');
$message->attach($htmlPart);
$message->attach($textPart);
//...
$mailer->send($message);
$textPart->setBody('Something Else');
$htmlPart->setBody('Something Else');
$message->setTo('someone.else@example.com');
$mailer->send($message);

您还可以使用

$message->detach($textPart);

他们不使用分离来迭代零件,查看addPartattach的工作方式,而是简单地调用setChildren(array_merge($this->getChildren(), array($part)))

因此,您可以通过定义子部分来手动设置子部分,这将替换调用addPartattach

$message->setChildren([$htmlPart, $textPart]);

出于所有意图和目的,如果您要删除消息的某些部分以及另一个收件人的不同内容(尽管只是轻微),那么您实际上是在创建新消息。编程逻辑可以通过在需要替换消息部分时调用$message = 'Swift_Message::newInstance()来反映这一点。

根据 Swift Mailer Docs,实际上没有getBody()这样的方法。

我建议您将包含占位符的实际消息模板存储在变量中,并在每次迭代中使用setBody()将消息的完整正文替换为新收件人的解析模板,而不是尝试替换其中的一小部分。

我认为您的代码可能如下所示:

$template = '<h1>Hello {{firstname}}</h1>, ...';
$recipients = [
    ['firstname' => 'John', 'email' => 'john@example.com'],
    ...
];
$message = Swift_Message::newInstance('Subject here');
foreach ($recipients as $recipient) {
    $body = str_replace('{{firstname}}', $recipient['firstname'], $template);
    $message->setBody($body, 'text/html');
    // continue building the mail object and send it ...
}

这样,您确实可以为每封邮件重复使用Swift_Message实例。尽管如果您在每次循环迭代中重用实例或创建一个新实例,这对 PHP 没有任何影响。

@tetranz 如@Hendrik大纲,您可以使用$message->getBody()$message->setBody($body)作为主体部分。

您可以通过与子级相同的方法访问(您提到的多部分addPart())部分。 即类似于:

$children = $message->getChildren();
foreach($children as &$child) {
    $c_body = $child->getBody();
    //manipulate as you wish
    $child->setBody($c_body);
}
$message->setChildren($children);

这适用于 Swift v5.0.1