magento2: Sending multiple emails using the TransportBuilder class causes an Zend_Mail exception
Preconditions
- Magento 2.2.3
- PHP 7.0.12
- MySQL 5.7.18
Steps to reproduce
- Fresh install of Magento
- Make a custom module with 2 observer classes on an event(‘sales_order_place_after’). Each of these observers should inject the TransportBuilder class and send an email:
$transport = $this->transportBuilder
->setTemplateIdentifier('email_template_identifier')
->setTemplateOptions([
'area' => \Magento\Framework\App\Area::AREA_FRONTEND,
'store' => 1
])
->setTemplateVars($data)
->setFrom($sender)
->addTo($mailto);
// important that this is its own line for when we override the transport builder due to how PHP polymorphism works :(
$transport = $this->transportBuilder->getTransport();
$transport->sendMessage();
- Checkout and place an order.
Expected result
- Two emails will be sent…
Actual result
- The first email is sent, the second email is never sent…
- The second observer will throw an exception in the $transport->sendMessage() function: throw new Zend_Mail_Exception(‘From Header set twice’);
- The system.log file will show the following line: “[2018-03-21 19:32:06] main.ERROR: From Header set twice [] []”
The issue seems to be that the transport builder is not adequately cleaning up the $message variable after getting the transport. The solution is to overwrite the TransportBuilder class, and in the function getTransport() to the following:
<?xml version="1.0" ?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<preference for="Magento\Framework\Mail\Template\TransportBuilder" type="Vendor\Module\Model\Mail\TransportBuilder" />
</config>
class TransportBuilder extends \Magento\Framework\Mail\Template\TransportBuilder
{
public function getTransport()
{
$mailTransport = parent::getTransport();
$this->message->clearFrom()
->clearReplyTo()
->clearReturnPath()
->clearSubject()
->clearMessageId()
->clearRecipients()
->setParts([]);
return $mailTransport;
}
}
Edit: I don’t feel that @dimonovp really reviewed this ticket. Can we have it reopened and reviewed?
About this issue
- Original URL
- State: closed
- Created 6 years ago
- Reactions: 1
- Comments: 26 (14 by maintainers)
@david-kominek, please refer to the Community Forums or the Magento Stack Exchange site for advice or general discussion about this issue. The GitHub issue tracker is intended for Magento Core technical issues only.
Fixed in 2.2-develop https://github.com/magento/magento2/commit/9a7c9e553b1c9814907105388bffc2e8a91353a5#diff-dfb3ee5a7f863458afea75f5524cd2e5
Is a bug indeed. Please re-open this issue.
here’s a core patch: bugfix–allow-more-than-one-email-being-sent.zip
please refrain from commenting the ugliness of the patch - mostly due to the stupidity of this bug. I’m sure someone can come up with a nicer solution eventually by getting rid of this dependency injection/object manager mess introduced in 2.2.4.
@magento-engcom-team Are you sure it is appropriate to close this ticket? This seems to be a real issue. TransportBuilder should not be usable once per request only. For example, what about an extension creating 5 shipments for different orders and emailing them to customers, in “one request/execution” – right now, using Magento\Sales\Model\Order\Email\Sender\ShipmentSender only the first of the five shipment emails would be sent, as after the first email, the above exception described by @david-kominek is stopping further emails from being sent.
we have this problem too, first noticed after updating to 2.2.4.
the TransportBuilder uses ObjectManager in reset() to create a “new”
\Magento\Framework\Mail\Message
instance:once a mail was previously created, the object returned from the ObjectManager won’t be a new, uniinitalized object and thus needs at least be reset properly. or get rid of the object manager stuff as everyone seems to preach nowadays.