Могу ли я заменить или удалить часть сообщения с помощью Swiftmailer?

Я использую Swift Mailer для отправки почты на довольно большой список адресов электронной почты. Сообщение немного настраивается для каждого получателя. Некоторые заполнители заменяются уникальным текстом.

Я предположил, что было бы более эффективно (меньше сборщика мусора и т. Д.) Повторно использовать один экземпляр Swift_Message несколько раз. Я просто setTo(), setBody() и снова отправляю на следующий адрес.

Это хорошо работает с телом, состоящим из одной части, обычно это просто html. Но ... когда мне нужна вторая часть, обычно текст, я могу сделать addPart(), но в следующий раз в цикле будет добавлена ​​еще одна часть, а затем еще одна часть и т. Д ... Проблема не возникает с setBody, потому что это перезаписывает существующее тело.

Есть ли способ перезаписать или удалить существующую деталь?

Спасибо


person tetranz    schedule 14.11.2013    source источник
comment
Я бы просто продолжал создавать новое сообщение в каждом цикле.   -  person Phil    schedule 15.11.2013


Ответы (3)


Чтобы расширить ответы Хендрика и Аласдера, я предлагаю изучить использование плагина Decorator. 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('[email protected]');
$message->attach($htmlPart);
$message->attach($textPart);
//...
$mailer->send($message);

$textPart->setBody('Something Else');
$htmlPart->setBody('Something Else');
$message->setTo('[email protected]');
$mailer->send($message);

Вы также можете удалить дочернюю часть, используя

$message->detach($textPart);

Вместо использования detach, который выполняет итерацию по частям, глядя на то, как работают addPart и attach, они просто вызывают setChildren(array_merge($this->getChildren(), array($part)))

Таким образом, вы можете установить дочерние части вручную, определив их, что заменяет вызов addPart или attach.

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

Для всех намерений и целей, если вы удаляете части сообщения вместе с другим содержимым (хотя и незначительно) для другого получателя, вы фактически создаете новое сообщение. Логика программирования может отражать это, вызывая $message = \Swift_Message::newInstance(), когда необходимо заменить части сообщения.

person Will B.    schedule 21.07.2016

Согласно Swift Mailer Docs, не существует такого метода, как getBody() действительно.

Я бы посоветовал вам сохранить фактическое сообщение template, содержащее ваши заполнители, в переменной и использовать setBody() на каждой итерации для замены всего тела сообщения проанализированным шаблоном для нового получателя вместо попытки заменить немного этого.

Я думаю, ваш код может выглядеть примерно так:

$template = '<h1>Hello {{firstname}}</h1>, ...';
$recipients = [
    ['firstname' => 'John', 'email' => '[email protected]'],
    ...
];
$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 не будет никакой разницы, если вы повторно используете экземпляр или создадите новый на каждой итерации цикла.

person Hendrik    schedule 08.02.2014
comment
Это нормально работает для односоставных сообщений, но проблема состоит в составных сообщениях, в которых вам нужно выполнить $ message- ›addPart (), чтобы установить вторую (обычно текстовую) часть. Детали накапливаются. Я менял его, чтобы каждый раз создавать новый экземпляр, и он отлично работает. Скорее всего, это было моей микрооптимизацией, чтобы в первую очередь беспокоиться об этом. - person tetranz; 09.02.2014

@tetranz Как отмечает @Hendrik, вы можете использовать $message->getBody() и $message->setBody($body) для основной части тела.

Вы можете получить доступ к частям (упомянутого вами multipart 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

person Alasdair    schedule 06.07.2015