diff --git a/app/code/Magento/Email/Model/Transport.php b/app/code/Magento/Email/Model/Transport.php
index 90a4e6571c9b..cbce1682cb5f 100644
--- a/app/code/Magento/Email/Model/Transport.php
+++ b/app/code/Magento/Email/Model/Transport.php
@@ -3,10 +3,13 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+declare(strict_types=1);
+
namespace Magento\Email\Model;
use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Framework\Exception\MailException;
+use Magento\Framework\Mail\EmailMessageInterface;
use Magento\Framework\Mail\MessageInterface;
use Magento\Framework\Mail\TransportInterface;
use Magento\Framework\Phrase;
@@ -59,12 +62,12 @@ class Transport implements TransportInterface
private $message;
/**
- * @param MessageInterface $message Email message object
+ * @param EmailMessageInterface $message Email message object
* @param ScopeConfigInterface $scopeConfig Core store config
* @param null|string|array|\Traversable $parameters Config options for sendmail parameters
*/
public function __construct(
- MessageInterface $message,
+ EmailMessageInterface $message,
ScopeConfigInterface $scopeConfig,
$parameters = null
) {
diff --git a/app/code/Magento/Newsletter/Model/Queue/TransportBuilder.php b/app/code/Magento/Newsletter/Model/Queue/TransportBuilder.php
index 502a19d298c4..aa3a2bcfe0f5 100644
--- a/app/code/Magento/Newsletter/Model/Queue/TransportBuilder.php
+++ b/app/code/Magento/Newsletter/Model/Queue/TransportBuilder.php
@@ -3,10 +3,29 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+declare(strict_types=1);
+
namespace Magento\Newsletter\Model\Queue;
use Magento\Email\Model\AbstractTemplate;
+use Magento\Framework\Exception\MailException;
+use Magento\Framework\Mail\EmailMessageInterfaceFactory;
+use Magento\Framework\Mail\AddressConverter;
+use Magento\Framework\Mail\MessageInterface;
+use Magento\Framework\Mail\MessageInterfaceFactory;
+use Magento\Framework\Mail\MimeMessageInterfaceFactory;
+use Magento\Framework\Mail\MimePartInterfaceFactory;
+use Magento\Framework\Mail\Template\FactoryInterface;
+use Magento\Framework\Mail\Template\SenderResolverInterface;
+use Magento\Framework\Mail\TemplateInterface;
+use Magento\Framework\Mail\TransportInterfaceFactory;
+use Magento\Framework\ObjectManagerInterface;
+/**
+ * Class TransportBuilder
+ *
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ */
class TransportBuilder extends \Magento\Framework\Mail\Template\TransportBuilder
{
/**
@@ -16,6 +35,194 @@ class TransportBuilder extends \Magento\Framework\Mail\Template\TransportBuilder
*/
protected $templateData = [];
+ /**
+ * Param that used for storing all message data until it will be used
+ *
+ * @var array
+ */
+ private $messageData = [];
+
+ /**
+ * @var EmailMessageInterfaceFactory
+ */
+ private $emailMessageInterfaceFactory;
+
+ /**
+ * @var MimeMessageInterfaceFactory
+ */
+ private $mimeMessageInterfaceFactory;
+
+ /**
+ * @var MimePartInterfaceFactory
+ */
+ private $mimePartInterfaceFactory;
+
+ /**
+ * @var AddressConverter|null
+ */
+ private $addressConverter;
+
+ /**
+ * TransportBuilder constructor
+ *
+ * @param FactoryInterface $templateFactory
+ * @param MessageInterface $message
+ * @param SenderResolverInterface $senderResolver
+ * @param ObjectManagerInterface $objectManager
+ * @param TransportInterfaceFactory $mailTransportFactory
+ * @param MessageInterfaceFactory|null $messageFactory
+ * @param EmailMessageInterfaceFactory|null $emailMessageInterfaceFactory
+ * @param MimeMessageInterfaceFactory|null $mimeMessageInterfaceFactory
+ * @param MimePartInterfaceFactory|null $mimePartInterfaceFactory
+ * @param AddressConverter|null $addressConverter
+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+ * @SuppressWarnings(PHPMD.ExcessiveParameterList)
+ */
+ public function __construct(
+ FactoryInterface $templateFactory,
+ MessageInterface $message,
+ SenderResolverInterface $senderResolver,
+ ObjectManagerInterface $objectManager,
+ TransportInterfaceFactory $mailTransportFactory,
+ MessageInterfaceFactory $messageFactory = null,
+ EmailMessageInterfaceFactory $emailMessageInterfaceFactory = null,
+ MimeMessageInterfaceFactory $mimeMessageInterfaceFactory = null,
+ MimePartInterfaceFactory $mimePartInterfaceFactory = null,
+ AddressConverter $addressConverter = null
+ ) {
+ parent::__construct(
+ $templateFactory,
+ $message,
+ $senderResolver,
+ $objectManager,
+ $mailTransportFactory,
+ $messageFactory,
+ $emailMessageInterfaceFactory,
+ $mimeMessageInterfaceFactory,
+ $mimePartInterfaceFactory,
+ $addressConverter
+ );
+ $this->emailMessageInterfaceFactory = $emailMessageInterfaceFactory ?: $this->objectManager
+ ->get(EmailMessageInterfaceFactory::class);
+ $this->mimeMessageInterfaceFactory = $mimeMessageInterfaceFactory ?: $this->objectManager
+ ->get(MimeMessageInterfaceFactory::class);
+ $this->mimePartInterfaceFactory = $mimePartInterfaceFactory ?: $this->objectManager
+ ->get(MimePartInterfaceFactory::class);
+ $this->addressConverter = $addressConverter ?: $this->objectManager
+ ->get(AddressConverter::class);
+ }
+
+ /**
+ * Add cc address
+ *
+ * @param array|string $address
+ * @param string $name
+ *
+ * @return \Magento\Framework\Mail\Template\TransportBuilder
+ * @throws MailException
+ */
+ public function addCc($address, $name = '')
+ {
+ $this->addAddressByType('cc', $address, $name);
+
+ return $this;
+ }
+
+ /**
+ * Add to address
+ *
+ * @param array|string $address
+ * @param string $name
+ *
+ * @return $this
+ * @throws MailException
+ */
+ public function addTo($address, $name = '')
+ {
+ $this->addAddressByType('to', $address, $name);
+
+ return $this;
+ }
+
+ /**
+ * Add bcc address
+ *
+ * @param array|string $address
+ *
+ * @return $this
+ * @throws MailException
+ */
+ public function addBcc($address)
+ {
+ $this->addAddressByType('bcc', $address);
+
+ return $this;
+ }
+
+ /**
+ * Set Reply-To Header
+ *
+ * @param string $email
+ * @param string|null $name
+ *
+ * @return $this
+ * @throws MailException
+ */
+ public function setReplyTo($email, $name = null)
+ {
+
+ $this->addAddressByType('replyTo', $email, $name);
+
+ return $this;
+ }
+
+ /**
+ * Set mail from address
+ *
+ * @param string|array $from
+ *
+ * @return $this
+ * @throws MailException
+ * @see setFromByScope()
+ *
+ * @deprecated This function sets the from address but does not provide
+ * a way of setting the correct from addresses based on the scope.
+ */
+ public function setFrom($from)
+ {
+ return $this->setFromByScope($from);
+ }
+
+ /**
+ * Set mail from address by scopeId
+ *
+ * @param string|array $from
+ * @param string|int $scopeId
+ *
+ * @return $this
+ * @throws MailException
+ */
+ public function setFromByScope($from, $scopeId = null)
+ {
+ $result = $this->_senderResolver->resolve($from, $scopeId);
+ $this->addAddressByType('from', $result['email'], $result['name']);
+
+ return $this;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ protected function reset()
+ {
+ $this->messageData = [];
+ $this->templateIdentifier = null;
+ $this->templateVars = null;
+ $this->templateOptions = null;
+
+ return $this;
+ }
+
/**
* Set template data
*
@@ -25,11 +232,15 @@ class TransportBuilder extends \Magento\Framework\Mail\Template\TransportBuilder
public function setTemplateData($data)
{
$this->templateData = $data;
+
return $this;
}
/**
+ * Sets up template filter
+ *
* @param AbstractTemplate $template
+ *
* @return void
*/
protected function setTemplateFilter(AbstractTemplate $template)
@@ -44,16 +255,44 @@ protected function setTemplateFilter(AbstractTemplate $template)
*/
protected function prepareMessage()
{
- /** @var AbstractTemplate $template */
+ /** @var AbstractTemplate|TemplateInterface $template */
$template = $this->getTemplate()->setData($this->templateData);
$this->setTemplateFilter($template);
+ $content = $template->getProcessedTemplate($this->templateVars);
+ $this->messageData['subject'] = $template->getSubject();
- $this->message->setBodyHtml(
- $template->getProcessedTemplate($this->templateVars)
- )->setSubject(
- $template->getSubject()
+ $mimePart = $this->mimePartInterfaceFactory->create(
+ ['content' => $content]
+ );
+ $this->messageData['body'] = $this->mimeMessageInterfaceFactory->create(
+ ['parts' => [$mimePart]]
);
+ $this->message = $this->emailMessageInterfaceFactory->create($this->messageData);
+
return $this;
}
+
+ /**
+ * Handles possible incoming types of email (string or array)
+ *
+ * @param string $addressType
+ * @param string|array $email
+ * @param string|null $name
+ *
+ * @return void
+ * @throws MailException
+ */
+ private function addAddressByType(string $addressType, $email, ?string $name = null): void
+ {
+ if (is_array($email)) {
+ $this->messageData[$addressType] = array_merge(
+ $this->messageData[$addressType],
+ $this->addressConverter->convertMany($email)
+ );
+
+ return;
+ }
+ $this->messageData[$addressType][] = $this->addressConverter->convert($email, $name);
+ }
}
diff --git a/app/code/Magento/Newsletter/Test/Unit/Model/Queue/TransportBuilderTest.php b/app/code/Magento/Newsletter/Test/Unit/Model/Queue/TransportBuilderTest.php
index e8b141a24c9e..8f5626b42ff3 100644
--- a/app/code/Magento/Newsletter/Test/Unit/Model/Queue/TransportBuilderTest.php
+++ b/app/code/Magento/Newsletter/Test/Unit/Model/Queue/TransportBuilderTest.php
@@ -1,78 +1,112 @@
-templateFactoryMock = $this->createMock(\Magento\Framework\Mail\Template\FactoryInterface::class);
- $this->messageMock = $this->getMockBuilder(\Magento\Framework\Mail\MessageInterface::class)
+ $objectManagerHelper = new ObjectManager($this);
+ $this->templateFactoryMock = $this->createMock(FactoryInterface::class);
+ $this->messageMock = $this->getMockBuilder(MessageInterface::class)
->disableOriginalConstructor()
->setMethods(['setBodyHtml', 'setSubject'])
->getMockForAbstractClass();
- $this->objectManagerMock = $this->createMock(\Magento\Framework\ObjectManagerInterface::class);
- $this->senderResolverMock = $this->createMock(\Magento\Framework\Mail\Template\SenderResolverInterface::class);
- $this->mailTransportFactoryMock = $this->getMockBuilder(
- \Magento\Framework\Mail\TransportInterfaceFactory::class
- )->disableOriginalConstructor()
- ->setMethods(['create'])
- ->getMock();
- $this->messageFactoryMock = $this->getMockBuilder(\Magento\Framework\Mail\MessageInterfaceFactory::class)
+
+ $this->emailMessageInterfaceFactoryMock = $this->createMock(EmailMessageInterfaceFactory::class);
+ $this->mimePartFactoryMock = $this->createMock(MimePartInterfaceFactory::class);
+
+ $this->objectManagerMock = $this->createMock(ObjectManagerInterface::class);
+ $this->senderResolverMock = $this->createMock(SenderResolverInterface::class);
+ $this->mailTransportFactoryMock = $this->getMockBuilder(TransportInterfaceFactory::class)
->disableOriginalConstructor()
->setMethods(['create'])
- ->getMockForAbstractClass();
- $this->messageFactoryMock->expects($this->atLeastOnce())->method('create')->willReturn($this->messageMock);
+ ->getMock();
+
$this->builder = $objectManagerHelper->getObject(
$this->builderClassName,
[
@@ -81,7 +115,9 @@ public function setUp()
'objectManager' => $this->objectManagerMock,
'senderResolver' => $this->senderResolverMock,
'mailTransportFactory' => $this->mailTransportFactoryMock,
- 'messageFactory' => $this->messageFactoryMock
+ 'messageFactory' => $this->messageFactoryMock,
+ 'emailMessageInterfaceFactory' => $this->emailMessageInterfaceFactoryMock,
+ 'mimePartInterfaceFactory' => $this->mimePartFactoryMock,
]
);
}
@@ -91,12 +127,13 @@ public function setUp()
* @param string $bodyText
* @return void
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+ * @throws \Magento\Framework\Exception\LocalizedException
*/
public function testGetTransport(
$templateType = TemplateTypesInterface::TYPE_HTML,
$bodyText = '
Html message
'
- ) {
- $filter = $this->createMock(\Magento\Email\Model\Template\Filter::class);
+ ): void {
+ $filter = $this->createMock(Filter::class);
$data = [
'template_subject' => 'Email Subject',
'template_text' => $bodyText,
@@ -106,39 +143,39 @@ public function testGetTransport(
];
$vars = ['reason' => 'Reason', 'customer' => 'Customer'];
$options = ['area' => 'frontend', 'store' => 1];
- $template = $this->createMock(\Magento\Email\Model\Template::class);
- $template->expects($this->once())->method('setVars')->with($this->equalTo($vars))->will($this->returnSelf());
- $template->expects(
- $this->once()
- )->method(
- 'setOptions'
- )->with(
- $this->equalTo($options)
- )->will(
- $this->returnSelf()
- );
- $template->expects($this->once())->method('getSubject')->will($this->returnValue('Email Subject'));
- $template->expects($this->once())->method('setData')->with($this->equalTo($data))->will($this->returnSelf());
- $template->expects($this->once())
- ->method('getProcessedTemplate')
- ->with($vars)
- ->willReturn($bodyText);
- $template->expects($this->once())
- ->method('setTemplateFilter')
- ->with($filter);
- $this->templateFactoryMock->expects(
- $this->once()
- )->method(
- 'get'
- )->with(
- $this->equalTo('identifier')
- )->will(
- $this->returnValue($template)
- );
+ /** @var MimePartInterface|MockObject $mimePartMock */
+ $mimePartMock = $this->createMock(MimePartInterface::class);
+
+ $this->mimePartFactoryMock->expects($this->any())
+ ->method('create')
+ ->willReturn($mimePartMock);
+
+ /** @var EmailMessageInterface|MockObject $emailMessage */
+ $emailMessage = $this->createMock(EmailMessageInterface::class);
+
+ $this->emailMessageInterfaceFactoryMock->expects($this->any())
+ ->method('create')
+ ->willReturn($emailMessage);
+
+ $template = $this->createMock(Template::class);
+ $template->expects($this->once())->method('setVars')
+ ->with($this->equalTo($vars))->will($this->returnSelf());
+ $template->expects($this->once())->method('setOptions')
+ ->with($this->equalTo($options))->will($this->returnSelf());
+ $template->expects($this->once())->method('getSubject')
+ ->willReturn('Email Subject');
+ $template->expects($this->once())->method('setData')
+ ->with($this->equalTo($data))->will($this->returnSelf());
+ $template->expects($this->once())->method('getProcessedTemplate')
+ ->with($vars)->willReturn($bodyText);
+ $template->expects($this->once())->method('setTemplateFilter')
+ ->with($filter);
- $this->messageMock->expects($this->once())->method('setBodyHtml')->willReturnSelf();
- $this->messageMock->expects($this->once())->method('setSubject')->willReturnSelf();
+ $this->templateFactoryMock->expects($this->once())
+ ->method('get')
+ ->with($this->equalTo('identifier'))
+ ->willReturn($template);
$this->builder->setTemplateIdentifier(
'identifier'
diff --git a/app/etc/di.xml b/app/etc/di.xml
index afe8f36b7de8..1a74fd9d7f84 100755
--- a/app/etc/di.xml
+++ b/app/etc/di.xml
@@ -1771,4 +1771,10 @@
+
+
+
diff --git a/composer.json b/composer.json
index 7235e75f2326..c4744962b50f 100644
--- a/composer.json
+++ b/composer.json
@@ -68,6 +68,7 @@
"zendframework/zend-json": "^2.6.1",
"zendframework/zend-log": "^2.9.1",
"zendframework/zend-mail": "^2.9.0",
+ "zendframework/zend-mime": "^2.5.0",
"zendframework/zend-modulemanager": "^2.7",
"zendframework/zend-mvc": "~2.7.0",
"zendframework/zend-serializer": "^2.7.2",
diff --git a/composer.lock b/composer.lock
index 8c9f79cac256..591e51c62e83 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "0cf49b3b5a47076608e87c7ddb566073",
+ "content-hash": "f6c85e01a374b22a185f11a0c51e08fb",
"packages": [
{
"name": "braintree/braintree_php",
diff --git a/dev/tests/integration/testsuite/Magento/Customer/Controller/AccountTest.php b/dev/tests/integration/testsuite/Magento/Customer/Controller/AccountTest.php
index b80f00b16f0b..566dfbadedd2 100644
--- a/dev/tests/integration/testsuite/Magento/Customer/Controller/AccountTest.php
+++ b/dev/tests/integration/testsuite/Magento/Customer/Controller/AccountTest.php
@@ -769,7 +769,7 @@ public function testConfirmationEmailWithSpecialCharacters(): void
$message = $this->transportBuilderMock->getSentMessage();
$rawMessage = $message->getRawMessage();
- $this->assertContains('To: ' . $email, $rawMessage);
+ $this->assertContains('To: John Smith <' . $email . '>', $rawMessage);
$content = $message->getBody()->getParts()[0]->getRawContent();
$confirmationUrl = $this->getConfirmationUrlFromMessageContent($content);
diff --git a/dev/tests/integration/testsuite/Magento/Framework/Mail/EmailMessageTest.php b/dev/tests/integration/testsuite/Magento/Framework/Mail/EmailMessageTest.php
new file mode 100644
index 000000000000..10a54b4e1b87
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Framework/Mail/EmailMessageTest.php
@@ -0,0 +1,268 @@
+ [
+ ['email' => 'to@adobe.com', 'name' => 'Addressee']
+ ],
+ 'replyTo' => ['email' => 'replyTo@adobe.com', 'name' => 'Reply To Address'],
+ 'from' => 'from@adobe.com',
+ 'sender' => ['email' => 'sender@adobe.com', 'name' => 'Sender'],
+ 'cc' => [
+ 'cc1@adobe.com' => 'CC 1 Address',
+ 'cc2@adobe.com' => 'CC 2 Address',
+ 'cc3@adobe.com' => 'CC 3 Address',
+ ],
+ 'bcc' => ['bcc1@adobe.com', 'bcc2@adobe.com'],
+ ];
+
+ /**
+ * @var string
+ */
+ private $subject = 'Test subject';
+
+ /**
+ * @var string
+ */
+ private $description = 'Test description';
+
+ /**
+ *
+ * @return void
+ */
+ protected function setUp()
+ {
+ $this->di = Bootstrap::getObjectManager();
+ $this->mimePartFactory = $this->di->get(MimePartInterfaceFactory::class);
+ $this->mimeMessageFactory = $this->di->get(MimeMessageInterfaceFactory::class);
+ $this->messageConverter = $this->di->get(AddressConverter::class);
+ $this->messageFactory = $this->di->get(EmailMessageInterfaceFactory::class);
+ }
+
+ /**
+ * @return array
+ */
+ public function getEmailMessageDataProvider(): array
+ {
+ return [
+ [
+ 'Content Test',
+ MimeInterface::TYPE_TEXT
+ ], [
+
+ 'Html message
',
+ MimeInterface::TYPE_HTML
+ ]
+ ];
+ }
+
+ /**
+ * Tests Email Message with Addresses
+ *
+ * @dataProvider getEmailMessageDataProvider
+ * @param $content
+ * @param $type
+ * @return void
+ * @throws MailException
+ */
+ public function testEmailMessage($content, $type): void
+ {
+ $mimePart = $this->mimePartFactory->create(
+ [
+ 'content' => $content,
+ 'description' => $this->description,
+ 'type' => $type
+ ]
+ );
+
+ $mimeMessage = $this->mimeMessageFactory->create(
+ [
+ 'parts' => [$mimePart]
+ ]
+ );
+
+ $this->addressFactory = $this->di->get(AddressFactory::class);
+ /** @var Address $addressTo */
+ $to = [
+ $this->addressFactory->create(
+ [
+ 'email' => $this->addressList['to'][0]['email'],
+ 'name' => $this->addressList['to'][0]['name']
+ ]
+ )
+ ];
+
+ $from = [$this->messageConverter->convert($this->addressList['from'])];
+ $cc = $this->messageConverter->convertMany($this->addressList['cc']);
+ $replyTo = [
+ $this->messageConverter->convert(
+ $this->addressList['replyTo']['email'],
+ $this->addressList['replyTo']['name']
+ )
+ ];
+ $bcc = $this->messageConverter->convertMany($this->addressList['bcc']);
+ $sender = $this->messageConverter->convert(
+ $this->addressList['sender']['email'],
+ $this->addressList['sender']['name']
+ );
+ $data = [
+ 'body' => $mimeMessage,
+ 'subject' => $this->subject,
+ 'from' => $from,
+ 'to' => $to,
+ 'cc' => $cc,
+ 'replyTo' => $replyTo,
+ 'bcc' => $bcc,
+ 'sender' => $sender
+ ];
+ $message = $this->messageFactory->create($data);
+
+ $this->assertContains($content, $message->toString());
+ $this->assertContains('Content-Type: ' . $type, $message->toString());
+ $senderString = 'Sender: ' . $sender->getName() . ' <' . $sender->getEmail() . '>';
+ $this->assertContains($senderString, $message->toString());
+ $this->assertContains('From: ' . $from[0]->getEmail(), $message->toString());
+ $replyToString = 'Reply-To: ' . $replyTo[0]->getName() . ' <' . $replyTo[0]->getEmail() . '>';
+ $this->assertContains($replyToString, $message->toString());
+ $toString = 'To: ' . $to[0]->getName() . ' <' . $to[0]->getEmail() . '>';
+ $this->assertContains($toString, $message->toString());
+ $ccString = 'Cc: ' . $cc[0]->getName() . ' <' . $cc[0]->getEmail() . '>';
+ $this->assertContains($ccString, $message->toString());
+ $this->assertContains('Bcc: ' . $bcc[0]->getEmail(), $message->toString());
+ $this->assertContains('Content-Description: ' . $this->description, $message->toString());
+ $this->assertContains('Subject: ' . $this->subject, $message->toString());
+ $this->assertContains($content, $message->toString());
+ //tests address factory
+ $this->assertInstanceOf(Address::class, $message->getTo()[0]);
+ //tests address converter convert method
+ $this->assertInstanceOf(Address::class, $message->getFrom()[0]);
+ //tests address converter convertMany method
+ $this->assertInstanceOf(Address::class, $message->getCc()[0]);
+ }
+
+ /**
+ * Test Email Message with Xml Attachment
+ *
+ * @return void
+ */
+ public function testEmailMessageWithAttachment(): void
+ {
+ $mimePartMain = $this->mimePartFactory->create(
+ [
+ 'content' => 'Test',
+ 'description' => $this->description,
+ 'type' => MimeInterface::TYPE_TEXT
+ ]
+ );
+ $mimePartAttachment = $this->mimePartFactory->create(
+ [
+ 'content' => $this->getXmlContent(),
+ 'disposition' => MimeInterface::DISPOSITION_ATTACHMENT,
+ 'fileName' => self::ATTACHMENT_FILE_NAME,
+ 'encoding' => MimeInterface::ENCODING_8BIT,
+ 'type' => self::XML_TYPE
+ ]
+ );
+
+ $mimeMessage = $this->mimeMessageFactory->create(
+ [
+ 'parts' => [$mimePartMain, $mimePartAttachment]
+ ]
+ );
+
+ $this->addressFactory = $this->di->get(AddressFactory::class);
+ /** @var Address $addressTo */
+ $addressTo = $this->addressFactory
+ ->create(
+ [
+ 'email' => $this->addressList['to'][0]['email'],
+ 'name' => $this->addressList['to'][0]['name']
+ ]
+ );
+
+ $data = [
+ 'body' => $mimeMessage,
+ 'subject' => $this->subject,
+ 'to' => [$addressTo],
+ ];
+ $message = $this->messageFactory->create($data);
+
+ $this->assertContains($this->getXmlContent(), $message->toString());
+ $this->assertContains('Content-Type: ' . self::XML_TYPE, $message->toString());
+ $contentDisposition = 'Content-Disposition: ' . MimeInterface::DISPOSITION_ATTACHMENT
+ . '; filename="' . self::ATTACHMENT_FILE_NAME . '"';
+ $this->assertContains($contentDisposition, $message->toString());
+ }
+
+ /**
+ * Provides xml content
+ *
+ * @return string
+ */
+ private function getXmlContent(): string
+ {
+ return '
+
+
+
+
+ - Furman\Test\Command\Testbed
+
+
+
+
+';
+ }
+}
diff --git a/dev/tests/static/testsuite/Magento/Test/Php/_files/phpcpd/blacklist/common.txt b/dev/tests/static/testsuite/Magento/Test/Php/_files/phpcpd/blacklist/common.txt
index e59cd0983da1..4653203f4d57 100644
--- a/dev/tests/static/testsuite/Magento/Test/Php/_files/phpcpd/blacklist/common.txt
+++ b/dev/tests/static/testsuite/Magento/Test/Php/_files/phpcpd/blacklist/common.txt
@@ -216,3 +216,5 @@ Magento/Elasticsearch6/Model/Client
Magento/Config/App/Config/Type
Magento/InventoryReservationCli/Test/Integration
Magento/InventoryAdminUi/Controller/Adminhtml
+Magento/Newsletter/Model/Queue/TransportBuilder
+Magento/Framework/Mail/Template/TransportBuilder
\ No newline at end of file
diff --git a/lib/internal/Magento/Framework/Mail/Address.php b/lib/internal/Magento/Framework/Mail/Address.php
new file mode 100644
index 000000000000..18e1a8c72f21
--- /dev/null
+++ b/lib/internal/Magento/Framework/Mail/Address.php
@@ -0,0 +1,58 @@
+email = $email;
+ $this->name = $name;
+ }
+
+ /**
+ * Name getter
+ *
+ * @return string|null
+ */
+ public function getName(): ?string
+ {
+ return $this->name;
+ }
+
+ /**
+ * Email getter
+ *
+ * @return string
+ */
+ public function getEmail(): string
+ {
+ return $this->email;
+ }
+}
diff --git a/lib/internal/Magento/Framework/Mail/AddressConverter.php b/lib/internal/Magento/Framework/Mail/AddressConverter.php
new file mode 100644
index 000000000000..d787482f1757
--- /dev/null
+++ b/lib/internal/Magento/Framework/Mail/AddressConverter.php
@@ -0,0 +1,82 @@
+addressFactory = $addressFactory;
+ }
+
+ /**
+ * Creates MailAddress from string values
+ *
+ * @param string $email
+ * @param string|null $name
+ *
+ * @return Address
+ */
+ public function convert(string $email, ?string $name = null): Address
+ {
+ return $this->addressFactory->create(
+ [
+ 'name' => $name,
+ 'email' => $email
+ ]
+ );
+ }
+
+ /**
+ * Converts array to list of MailAddresses
+ *
+ * @param array $addresses
+ *
+ * @return Address[]
+ * @throws InvalidArgumentException
+ */
+ public function convertMany(array $addresses): array
+ {
+ $addressList = [];
+ foreach ($addresses as $key => $value) {
+
+ if (is_int($key) || is_numeric($key)) {
+ $addressList[] = $this->convert($value);
+ continue;
+ }
+
+ if (!is_string($key)) {
+ throw new InvalidArgumentException(
+ sprintf(
+ 'Invalid key type in provided addresses array ("%s")',
+ (is_object($key) ? get_class($key) : var_export($key, 1))
+ )
+ );
+ }
+ $addressList[] = $this->convert($key, $value);
+ }
+
+ return $addressList;
+ }
+}
diff --git a/lib/internal/Magento/Framework/Mail/EmailMessage.php b/lib/internal/Magento/Framework/Mail/EmailMessage.php
new file mode 100644
index 000000000000..aaef97507518
--- /dev/null
+++ b/lib/internal/Magento/Framework/Mail/EmailMessage.php
@@ -0,0 +1,257 @@
+message = new ZendMessage();
+ $mimeMessage = new ZendMimeMessage();
+ $mimeMessage->setParts($body->getParts());
+ $this->message->setBody($mimeMessage);
+ if ($encoding) {
+ $this->message->setEncoding($encoding);
+ }
+ if ($subject) {
+ $this->message->setSubject($subject);
+ }
+ if ($sender) {
+ $this->message->setSender($sender->getEmail(), $sender->getName());
+ }
+ if (count($to) < 1) {
+ throw new InvalidArgumentException('Email message must have at list one addressee');
+ }
+ if ($to) {
+ $this->message->setTo($this->convertAddressArrayToAddressList($to));
+ }
+ if ($replyTo) {
+ $this->message->setReplyTo($this->convertAddressArrayToAddressList($replyTo));
+ }
+ if ($from) {
+ $this->message->setFrom($this->convertAddressArrayToAddressList($from));
+ }
+ if ($cc) {
+ $this->message->setCc($this->convertAddressArrayToAddressList($cc));
+ }
+ if ($bcc) {
+ $this->message->setBcc($this->convertAddressArrayToAddressList($bcc));
+ }
+ $this->mimeMessageFactory = $mimeMessageFactory;
+ $this->addressFactory = $addressFactory;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getEncoding(): string
+ {
+ return $this->message->getEncoding();
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getHeaders(): array
+ {
+ return $this->message->getHeaders()->toArray();
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getFrom(): ?array
+ {
+ return $this->convertAddressListToAddressArray($this->message->getFrom());
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getTo(): array
+ {
+ return $this->convertAddressListToAddressArray($this->message->getTo());
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getCc(): ?array
+ {
+ return $this->convertAddressListToAddressArray($this->message->getCc());
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getBcc(): ?array
+ {
+ return $this->convertAddressListToAddressArray($this->message->getBcc());
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getReplyTo(): ?array
+ {
+ return $this->convertAddressListToAddressArray($this->message->getReplyTo());
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getSender(): ?Address
+ {
+ /** @var ZendAddress $zendSender */
+ if (!$zendSender = $this->message->getSender()) {
+ return null;
+ }
+
+ return $this->addressFactory->create(
+ [
+ 'email' => $zendSender->getEmail(),
+ 'name' => $zendSender->getName()
+ ]
+ );
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getSubject(): ?string
+ {
+ return $this->message->getSubject();
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getBody(): MimeMessageInterface
+ {
+ return $this->mimeMessageFactory->create(
+ ['parts' => $this->message->getBody()->getParts()]
+ );
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getBodyText(): string
+ {
+ return $this->message->getBodyText();
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function getRawMessage(): string
+ {
+ return $this->toString();
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function toString(): string
+ {
+ return $this->message->toString();
+ }
+
+ /**
+ * Converts AddressList to array
+ *
+ * @param AddressList $addressList
+ * @return Address[]
+ */
+ private function convertAddressListToAddressArray(AddressList $addressList): array
+ {
+ $arrayList = [];
+ foreach ($addressList as $address) {
+ $arrayList[] =
+ $this->addressFactory->create(
+ [
+ 'email' => $address->getEmail(),
+ 'name' => $address->getName()
+ ]
+ );
+ }
+
+ return $arrayList;
+ }
+
+ /**
+ * Converts MailAddress array to AddressList
+ *
+ * @param Address[] $arrayList
+ * @return AddressList
+ */
+ private function convertAddressArrayToAddressList(array $arrayList): AddressList
+ {
+ $zendAddressList = new AddressList();
+ foreach ($arrayList as $address) {
+ $zendAddressList->add($address->getEmail(), $address->getName());
+ }
+
+ return $zendAddressList;
+ }
+}
diff --git a/lib/internal/Magento/Framework/Mail/EmailMessageInterface.php b/lib/internal/Magento/Framework/Mail/EmailMessageInterface.php
new file mode 100644
index 000000000000..95f83ff679cd
--- /dev/null
+++ b/lib/internal/Magento/Framework/Mail/EmailMessageInterface.php
@@ -0,0 +1,97 @@
+[\x21\x23-\x26\x2a\x2b\x2d\x5e\5f\60\x7b-\x7ea-zA-Z0-9]+)\?(?P[\x21\x23-\x26\x2a\x2b\x2d\x5e\5f\60\x7b-\x7ea-zA-Z0-9]+)\?(?P[\x21-\x3e\x40-\x7e]+)#';
+ // @codingStandardsIgnoreEnd
+}
diff --git a/lib/internal/Magento/Framework/Mail/MimeMessage.php b/lib/internal/Magento/Framework/Mail/MimeMessage.php
new file mode 100644
index 000000000000..4d783dafd1d7
--- /dev/null
+++ b/lib/internal/Magento/Framework/Mail/MimeMessage.php
@@ -0,0 +1,80 @@
+mimeMessage = new ZendMimeMessage();
+ $this->mimeMessage->setParts($parts);
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getParts(): array
+ {
+ return $this->mimeMessage->getParts();
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function isMultiPart(): bool
+ {
+ return $this->mimeMessage->isMultiPart();
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getMessage(string $endOfLine = MimeInterface::LINE_END): string
+ {
+ return $this->mimeMessage->generateMessage($endOfLine);
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getPartHeadersAsArray(int $partNum): array
+ {
+ return $this->mimeMessage->getPartHeadersArray($partNum);
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getPartHeaders(int $partNum, string $endOfLine = MimeInterface::LINE_END): string
+ {
+ return $this->mimeMessage->getPartHeaders($partNum, $endOfLine);
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getPartContent(int $partNum, string $endOfLine = MimeInterface::LINE_END): string
+ {
+ return $this->mimeMessage->getPartContent($partNum, $endOfLine);
+ }
+}
diff --git a/lib/internal/Magento/Framework/Mail/MimeMessageInterface.php b/lib/internal/Magento/Framework/Mail/MimeMessageInterface.php
new file mode 100644
index 000000000000..a272bcfd8980
--- /dev/null
+++ b/lib/internal/Magento/Framework/Mail/MimeMessageInterface.php
@@ -0,0 +1,65 @@
+mimePart = new ZendMimePart($content);
+ } catch (\Exception $e) {
+ throw new InvalidArgumentException($e->getMessage());
+ }
+ $this->mimePart->setType($type);
+ $this->mimePart->setEncoding($encoding);
+ $this->mimePart->setFilters($filters);
+ if ($charset) {
+ $this->mimePart->setBoundary($boundary);
+ }
+ if ($charset) {
+ $this->mimePart->setCharset($charset);
+ }
+ if ($disposition) {
+ $this->mimePart->setDisposition($disposition);
+ }
+ if ($description) {
+ $this->mimePart->setDescription($description);
+ }
+ if ($fileName) {
+ $this->mimePart->setFileName($fileName);
+ }
+ if ($location) {
+ $this->mimePart->setLocation($location);
+ }
+ if ($language) {
+ $this->mimePart->setLanguage($language);
+ }
+ if ($isStream) {
+ $this->mimePart->setIsStream($isStream);
+ }
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getType(): string
+ {
+ return $this->mimePart->getType();
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getEncoding(): string
+ {
+ return $this->mimePart->getEncoding();
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getDisposition(): string
+ {
+ return $this->mimePart->getDisposition();
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getDescription(): string
+ {
+ return $this->mimePart->getDescription();
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getFileName(): string
+ {
+ return $this->mimePart->getFileName();
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getCharset(): string
+ {
+ return $this->mimePart->getCharset();
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getBoundary(): string
+ {
+ return $this->mimePart->getBoundary();
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getLocation(): string
+ {
+ return $this->mimePart->getLocation();
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getLanguage(): string
+ {
+ return $this->mimePart->getLanguage();
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getFilters(): array
+ {
+ return $this->mimePart->getFilters();
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function isStream(): bool
+ {
+ return $this->mimePart->isStream();
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getEncodedStream($endOfLine = MimeInterface::LINE_END)
+ {
+ return $this->mimePart->getEncodedStream($endOfLine);
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getContent($endOfLine = MimeInterface::LINE_END)
+ {
+ return $this->mimePart->getContent($endOfLine);
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getRawContent(): string
+ {
+ return $this->mimePart->getRawContent();
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getHeadersArray($endOfLine = MimeInterface::LINE_END): array
+ {
+ return $this->mimePart->getHeadersArray($endOfLine);
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getHeaders($endOfLine = MimeInterface::LINE_END): string
+ {
+ return $this->mimePart->getHeaders($endOfLine);
+ }
+}
diff --git a/lib/internal/Magento/Framework/Mail/MimePartInterface.php b/lib/internal/Magento/Framework/Mail/MimePartInterface.php
new file mode 100644
index 000000000000..8a658cdf975c
--- /dev/null
+++ b/lib/internal/Magento/Framework/Mail/MimePartInterface.php
@@ -0,0 +1,133 @@
+templateFactory = $templateFactory;
$this->objectManager = $objectManager;
$this->_senderResolver = $senderResolver;
$this->mailTransportFactory = $mailTransportFactory;
- $this->messageFactory = $messageFactory ?: $this->objectManager->get(MessageInterfaceFactory::class);
- $this->message = $this->messageFactory->create();
+ $this->emailMessageInterfaceFactory = $emailMessageInterfaceFactory ?: $this->objectManager
+ ->get(EmailMessageInterfaceFactory::class);
+ $this->mimeMessageInterfaceFactory = $mimeMessageInterfaceFactory ?: $this->objectManager
+ ->get(MimeMessageInterfaceFactory::class);
+ $this->mimePartInterfaceFactory = $mimePartInterfaceFactory ?: $this->objectManager
+ ->get(MimePartInterfaceFactory::class);
+ $this->addressConverter = $addressConverter ?: $this->objectManager
+ ->get(AddressConverter::class);
}
/**
@@ -128,11 +177,13 @@ public function __construct(
*
* @param array|string $address
* @param string $name
+ *
* @return $this
*/
public function addCc($address, $name = '')
{
- $this->message->addCc($address, $name);
+ $this->addAddressByType('cc', $address, $name);
+
return $this;
}
@@ -141,11 +192,14 @@ public function addCc($address, $name = '')
*
* @param array|string $address
* @param string $name
+ *
* @return $this
+ * @throws InvalidArgumentException
*/
public function addTo($address, $name = '')
{
- $this->message->addTo($address, $name);
+ $this->addAddressByType('to', $address, $name);
+
return $this;
}
@@ -153,11 +207,14 @@ public function addTo($address, $name = '')
* Add bcc address
*
* @param array|string $address
+ *
* @return $this
+ * @throws InvalidArgumentException
*/
public function addBcc($address)
{
- $this->message->addBcc($address);
+ $this->addAddressByType('bcc', $address);
+
return $this;
}
@@ -166,28 +223,32 @@ public function addBcc($address)
*
* @param string $email
* @param string|null $name
+ *
* @return $this
+ * @throws InvalidArgumentException
*/
public function setReplyTo($email, $name = null)
{
- $this->message->setReplyTo($email, $name);
+ $this->addAddressByType('replyTo', $email, $name);
+
return $this;
}
/**
* Set mail from address
*
- * @deprecated This function sets the from address but does not provide
- * a way of setting the correct from addresses based on the scope.
- * @see setFromByScope()
- *
* @param string|array $from
+ *
* @return $this
- * @throws \Magento\Framework\Exception\MailException
+ * @throws InvalidArgumentException
+ * @see setFromByScope()
+ *
+ * @deprecated This function sets the from address but does not provide
+ * a way of setting the correct from addresses based on the scope.
*/
public function setFrom($from)
{
- return $this->setFromByScope($from, null);
+ return $this->setFromByScope($from);
}
/**
@@ -195,13 +256,16 @@ public function setFrom($from)
*
* @param string|array $from
* @param string|int $scopeId
+ *
* @return $this
- * @throws \Magento\Framework\Exception\MailException
+ * @throws InvalidArgumentException
+ * @throws MailException
*/
public function setFromByScope($from, $scopeId = null)
{
$result = $this->_senderResolver->resolve($from, $scopeId);
- $this->message->setFromAddress($result['email'], $result['name']);
+ $this->addAddressByType('from', $result['email'], $result['name']);
+
return $this;
}
@@ -209,11 +273,13 @@ public function setFromByScope($from, $scopeId = null)
* Set template identifier
*
* @param string $templateIdentifier
+ *
* @return $this
*/
public function setTemplateIdentifier($templateIdentifier)
{
$this->templateIdentifier = $templateIdentifier;
+
return $this;
}
@@ -221,6 +287,7 @@ public function setTemplateIdentifier($templateIdentifier)
* Set template model
*
* @param string $templateModel
+ *
* @return $this
*/
public function setTemplateModel($templateModel)
@@ -233,11 +300,13 @@ public function setTemplateModel($templateModel)
* Set template vars
*
* @param array $templateVars
+ *
* @return $this
*/
public function setTemplateVars($templateVars)
{
$this->templateVars = $templateVars;
+
return $this;
}
@@ -250,13 +319,14 @@ public function setTemplateVars($templateVars)
public function setTemplateOptions($templateOptions)
{
$this->templateOptions = $templateOptions;
+
return $this;
}
/**
* Get mail transport
*
- * @return \Magento\Framework\Mail\TransportInterface
+ * @return TransportInterface
* @throws LocalizedException
*/
public function getTransport()
@@ -278,7 +348,7 @@ public function getTransport()
*/
protected function reset()
{
- $this->message = $this->messageFactory->create();
+ $this->messageData = [];
$this->templateIdentifier = null;
$this->templateVars = null;
$this->templateOptions = null;
@@ -288,7 +358,7 @@ protected function reset()
/**
* Get template
*
- * @return \Magento\Framework\Mail\TemplateInterface
+ * @return TemplateInterface
*/
protected function getTemplate()
{
@@ -306,14 +376,14 @@ protected function getTemplate()
protected function prepareMessage()
{
$template = $this->getTemplate();
- $body = $template->processTemplate();
+ $content = $template->processTemplate();
switch ($template->getType()) {
case TemplateTypesInterface::TYPE_TEXT:
- $this->message->setBodyText($body);
+ $part['type'] = MimeInterface::TYPE_TEXT;
break;
case TemplateTypesInterface::TYPE_HTML:
- $this->message->setBodyHtml($body);
+ $part['type'] = MimeInterface::TYPE_HTML;
break;
default:
@@ -321,7 +391,42 @@ protected function prepareMessage()
new Phrase('Unknown template type')
);
}
- $this->message->setSubject(html_entity_decode($template->getSubject(), ENT_QUOTES));
+ $mimePart = $this->mimePartInterfaceFactory->create(['content' => $content]);
+ $this->messageData['body'] = $this->mimeMessageInterfaceFactory->create(
+ ['parts' => [$mimePart]]
+ );
+
+ $this->messageData['subject'] = html_entity_decode(
+ (string)$template->getSubject(),
+ ENT_QUOTES
+ );
+ $this->message = $this->emailMessageInterfaceFactory->create($this->messageData);
+
return $this;
}
+
+ /**
+ * Handles possible incoming types of email (string or array)
+ *
+ * @param string $addressType
+ * @param string|array $email
+ * @param string|null $name
+ *
+ * @return void
+ * @throws InvalidArgumentException
+ */
+ private function addAddressByType(string $addressType, $email, ?string $name = null): void
+ {
+ if (is_string($email)) {
+ $this->messageData[$addressType][] = $this->addressConverter->convert($email, $name);
+ return;
+ }
+ $convertedAddressArray = $this->addressConverter->convertMany($email);
+ if (isset($this->messageData[$addressType])) {
+ $this->messageData[$addressType] = array_merge(
+ $this->messageData[$addressType],
+ $convertedAddressArray
+ );
+ }
+ }
}
diff --git a/lib/internal/Magento/Framework/Mail/Test/Unit/Template/TransportBuilderTest.php b/lib/internal/Magento/Framework/Mail/Test/Unit/Template/TransportBuilderTest.php
index c9781281d353..74f40e76353f 100644
--- a/lib/internal/Magento/Framework/Mail/Test/Unit/Template/TransportBuilderTest.php
+++ b/lib/internal/Magento/Framework/Mail/Test/Unit/Template/TransportBuilderTest.php
@@ -3,50 +3,67 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+declare(strict_types=1);
namespace Magento\Framework\Mail\Test\Unit\Template;
use Magento\Framework\App\TemplateTypesInterface;
-use Magento\Framework\Mail\MessageInterface;
+use Magento\Framework\Mail\EmailMessageInterface;
+use Magento\Framework\Mail\EmailMessageInterfaceFactory;
+use Magento\Framework\Mail\Message;
use Magento\Framework\Mail\MessageInterfaceFactory;
+use Magento\Framework\Mail\MimePartInterface;
+use Magento\Framework\Mail\MimePartInterfaceFactory;
+use Magento\Framework\Mail\Template\FactoryInterface;
+use Magento\Framework\Mail\Template\SenderResolverInterface;
+use Magento\Framework\Mail\Template\TransportBuilder;
+use Magento\Framework\Mail\TemplateInterface;
+use Magento\Framework\Mail\TransportInterface;
+use Magento\Framework\Mail\TransportInterfaceFactory;
+use Magento\Framework\ObjectManagerInterface;
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
+use PHPUnit\Framework\MockObject\MockObject;
+use PHPUnit\Framework\TestCase;
/**
+ * Class TransportBuilderTest
+ *
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
-class TransportBuilderTest extends \PHPUnit\Framework\TestCase
+class TransportBuilderTest extends TestCase
{
/**
* @var string
*/
- protected $builderClassName = \Magento\Framework\Mail\Template\TransportBuilder::class;
+ protected $builderClassName = TransportBuilder::class;
/**
- * @var \Magento\Framework\Mail\Template\TransportBuilder
+ * @var TransportBuilder
*/
protected $builder;
/**
- * @var \Magento\Framework\Mail\Template\FactoryInterface | \PHPUnit_Framework_MockObject_MockObject
+ * @var FactoryInterface | \PHPUnit_Framework_MockObject_MockObject
*/
protected $templateFactoryMock;
/**
- * @var \Magento\Framework\Mail\Message | \PHPUnit_Framework_MockObject_MockObject
+ * @var Message | \PHPUnit_Framework_MockObject_MockObject
*/
protected $messageMock;
/**
- * @var \Magento\Framework\ObjectManagerInterface | \PHPUnit_Framework_MockObject_MockObject
+ * @var ObjectManagerInterface | \PHPUnit_Framework_MockObject_MockObject
*/
protected $objectManagerMock;
/**
- * @var \Magento\Framework\Mail\Template\SenderResolverInterface | \PHPUnit_Framework_MockObject_MockObject
+ * @var SenderResolverInterface | \PHPUnit_Framework_MockObject_MockObject
*/
protected $senderResolverMock;
/**
- * @var \Magento\Framework\Mail\MessageInterfaceFactory| \PHPUnit_Framework_MockObject_MockObject
+ * @var MessageInterfaceFactory| \PHPUnit_Framework_MockObject_MockObject
*/
private $messageFactoryMock;
@@ -55,26 +72,39 @@ class TransportBuilderTest extends \PHPUnit\Framework\TestCase
*/
protected $mailTransportFactoryMock;
+ /**
+ * @var MimePartInterfaceFactory|MockObject
+ */
+ private $mimePartFactoryMock;
+
+ /**
+ * @var EmailMessageInterfaceFactory|MockObject
+ */
+ private $emailMessageInterfaceFactoryMock;
+
/**
* @return void
*/
protected function setUp()
{
- $objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
- $this->templateFactoryMock = $this->createMock(\Magento\Framework\Mail\Template\FactoryInterface::class);
- $this->messageMock = $this->createMock(\Magento\Framework\Mail\Message::class);
- $this->objectManagerMock = $this->createMock(\Magento\Framework\ObjectManagerInterface::class);
- $this->senderResolverMock = $this->createMock(\Magento\Framework\Mail\Template\SenderResolverInterface::class);
+ $objectManagerHelper = new ObjectManager($this);
+ $this->templateFactoryMock = $this->createMock(FactoryInterface::class);
+ $this->messageMock = $this->createMock(Message::class);
+ $this->objectManagerMock = $this->createMock(ObjectManagerInterface::class);
+ $this->senderResolverMock = $this->createMock(SenderResolverInterface::class);
$this->mailTransportFactoryMock = $this->getMockBuilder(
- \Magento\Framework\Mail\TransportInterfaceFactory::class
+ TransportInterfaceFactory::class
)->disableOriginalConstructor()
->setMethods(['create'])
->getMockForAbstractClass();
- $this->messageFactoryMock = $this->getMockBuilder(\Magento\Framework\Mail\MessageInterfaceFactory::class)
+ $this->messageFactoryMock = $this->getMockBuilder(MessageInterfaceFactory::class)
->disableOriginalConstructor()
->setMethods(['create'])
->getMockForAbstractClass();
- $this->messageFactoryMock->expects($this->atLeastOnce())->method('create')->willReturn($this->messageMock);
+
+ $this->emailMessageInterfaceFactoryMock = $this->createMock(EmailMessageInterfaceFactory::class);
+ $this->mimePartFactoryMock = $this->createMock(MimePartInterfaceFactory::class);
+
$this->builder = $objectManagerHelper->getObject(
$this->builderClassName,
[
@@ -83,7 +113,9 @@ protected function setUp()
'objectManager' => $this->objectManagerMock,
'senderResolver' => $this->senderResolverMock,
'mailTransportFactory' => $this->mailTransportFactoryMock,
- 'messageFactory' => $this->messageFactoryMock
+ 'messageFactory' => $this->messageFactoryMock,
+ 'emailMessageInterfaceFactory' => $this->emailMessageInterfaceFactoryMock,
+ 'mimePartInterfaceFactory' => $this->mimePartFactoryMock,
]
);
}
@@ -91,19 +123,32 @@ protected function setUp()
/**
* @dataProvider getTransportDataProvider
* @param int $templateType
- * @param string $messageType
* @param string $bodyText
* @param string $templateNamespace
* @return void
*/
- public function testGetTransport($templateType, $messageType, $bodyText, $templateNamespace)
+ public function testGetTransport($templateType, $bodyText, $templateNamespace)
{
$this->builder->setTemplateModel($templateNamespace);
$vars = ['reason' => 'Reason', 'customer' => 'Customer'];
$options = ['area' => 'frontend', 'store' => 1];
- $template = $this->createMock(\Magento\Framework\Mail\TemplateInterface::class);
+ /** @var MimePartInterface|MockObject $mimePartMock */
+ $mimePartMock = $this->createMock(MimePartInterface::class);
+
+ $this->mimePartFactoryMock->expects($this->any())
+ ->method('create')
+ ->willReturn($mimePartMock);
+
+ /** @var EmailMessageInterface|MockObject $emailMessage */
+ $emailMessage = $this->createMock(EmailMessageInterface::class);
+
+ $this->emailMessageInterfaceFactoryMock->expects($this->any())
+ ->method('create')
+ ->willReturn($emailMessage);
+
+ $template = $this->createMock(TemplateInterface::class);
$template->expects($this->once())->method('setVars')->with($this->equalTo($vars))->willReturnSelf();
$template->expects($this->once())->method('setOptions')->with($this->equalTo($options))->willReturnSelf();
$template->expects($this->once())->method('getSubject')->willReturn('Email Subject');
@@ -115,32 +160,16 @@ public function testGetTransport($templateType, $messageType, $bodyText, $templa
->with($this->equalTo('identifier'), $this->equalTo($templateNamespace))
->willReturn($template);
- $this->messageMock->expects($this->once())
- ->method('setSubject')
- ->with($this->equalTo('Email Subject'))
- ->willReturnSelf();
-
- $this->messageMock->expects($this->exactly((int)($messageType == MessageInterface::TYPE_TEXT)))
- ->method('setBodyText')
- ->with($this->equalTo($bodyText))
- ->willReturnSelf();
-
- $this->messageMock->expects($this->exactly((int)($messageType == MessageInterface::TYPE_HTML)))
- ->method('setBodyHtml')
- ->with($this->equalTo($bodyText))
- ->willReturnSelf();
-
- $transport = $this->createMock(\Magento\Framework\Mail\TransportInterface::class);
+ $transport = $this->createMock(TransportInterface::class);
$this->mailTransportFactoryMock->expects($this->at(0))
->method('create')
- ->with($this->equalTo(['message' => $this->messageMock]))
->willReturn($transport);
- $this->messageFactoryMock->expects($this->once())->method('create')->willReturn($transport);
-
$this->builder->setTemplateIdentifier('identifier')->setTemplateVars($vars)->setTemplateOptions($options);
- $this->assertInstanceOf(\Magento\Framework\Mail\TransportInterface::class, $this->builder->getTransport());
+
+ $result = $this->builder->getTransport();
+ $this->assertInstanceOf(TransportInterface::class, $result);
}
/**
@@ -156,11 +185,10 @@ public function testGetTransportWithException()
$vars = ['reason' => 'Reason', 'customer' => 'Customer'];
$options = ['area' => 'frontend', 'store' => 1];
- $template = $this->createMock(\Magento\Framework\Mail\TemplateInterface::class);
+ $template = $this->createMock(TemplateInterface::class);
$template->expects($this->once())->method('setVars')->with($this->equalTo($vars))->willReturnSelf();
$template->expects($this->once())->method('setOptions')->with($this->equalTo($options))->willReturnSelf();
$template->expects($this->once())->method('getType')->willReturn('Unknown');
- $this->messageFactoryMock->expects($this->once())->method('create');
$this->templateFactoryMock->expects($this->once())
->method('get')
->with($this->equalTo('identifier'), $this->equalTo('Test\Namespace\Template'))
@@ -168,7 +196,7 @@ public function testGetTransportWithException()
$this->builder->setTemplateIdentifier('identifier')->setTemplateVars($vars)->setTemplateOptions($options);
- $this->assertInstanceOf(\Magento\Framework\Mail\TransportInterface::class, $this->builder->getTransport());
+ $this->assertInstanceOf(TransportInterface::class, $this->builder->getTransport());
}
/**
@@ -179,13 +207,11 @@ public function getTransportDataProvider()
return [
[
TemplateTypesInterface::TYPE_TEXT,
- MessageInterface::TYPE_TEXT,
'Plain text',
null
],
[
TemplateTypesInterface::TYPE_HTML,
- MessageInterface::TYPE_HTML,
'Html message
',
'Test\Namespace\Template'
]
@@ -203,60 +229,7 @@ public function testSetFromByScope()
->method('resolve')
->with($sender, $scopeId)
->willReturn($sender);
- $this->messageMock->expects($this->once())
- ->method('setFromAddress')
- ->with($sender['email'], $sender['name'])
- ->willReturnSelf();
$this->builder->setFromByScope($sender, $scopeId);
}
-
- /**
- * @return void
- */
- public function testSetCc()
- {
- $this->messageMock->expects($this->once())->method('addCc')->with('cc@example.com')->willReturnSelf();
-
- $this->builder->addCc('cc@example.com');
- }
-
- /**
- * @return void
- */
- public function testAddTo()
- {
- $this->messageMock->expects($this->once())
- ->method('addTo')
- ->with('to@example.com', 'recipient')
- ->willReturnSelf();
-
- $this->builder->addTo('to@example.com', 'recipient');
- }
-
- /**
- * @return void
- */
- public function testAddBcc()
- {
- $this->messageMock->expects($this->once())
- ->method('addBcc')
- ->with('bcc@example.com')
- ->willReturnSelf();
-
- $this->builder->addBcc('bcc@example.com');
- }
-
- /**
- * @return void
- */
- public function testSetReplyTo()
- {
- $this->messageMock->expects($this->once())
- ->method('setReplyTo')
- ->with('replyTo@example.com', 'replyName')
- ->willReturnSelf();
-
- $this->builder->setReplyTo('replyTo@example.com', 'replyName');
- }
}
diff --git a/lib/internal/Magento/Framework/Mail/TransportInterfaceFactory.php b/lib/internal/Magento/Framework/Mail/TransportInterfaceFactory.php
index db86275954cb..5448df4e16ca 100644
--- a/lib/internal/Magento/Framework/Mail/TransportInterfaceFactory.php
+++ b/lib/internal/Magento/Framework/Mail/TransportInterfaceFactory.php
@@ -3,9 +3,12 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+declare(strict_types=1);
namespace Magento\Framework\Mail;
+use Magento\Framework\ObjectManagerInterface;
+
/**
* Factory class for \Magento\Framework\Mail\TransportInterface
*/
@@ -14,39 +17,39 @@ class TransportInterfaceFactory
/**
* Object Manager instance
*
- * @var \Magento\Framework\ObjectManagerInterface
+ * @var ObjectManagerInterface
*/
- protected $_objectManager = null;
+ private $objectManager;
/**
* Instance name to create
*
* @var string
*/
- protected $_instanceName = null;
+ private $instanceName;
/**
* Factory constructor
*
- * @param \Magento\Framework\ObjectManagerInterface $objectManager
+ * @param ObjectManagerInterface $objectManager
* @param string $instanceName
*/
public function __construct(
- \Magento\Framework\ObjectManagerInterface $objectManager,
- $instanceName = \Magento\Framework\Mail\TransportInterface::class
+ ObjectManagerInterface $objectManager,
+ $instanceName = TransportInterface::class
) {
- $this->_objectManager = $objectManager;
- $this->_instanceName = $instanceName;
+ $this->objectManager = $objectManager;
+ $this->instanceName = $instanceName;
}
/**
* Create class instance with specified parameters
*
* @param array $data
- * @return \Magento\Framework\Mail\TransportInterface
+ * @return TransportInterface
*/
- public function create(array $data = [])
+ public function create(array $data = []): TransportInterface
{
- return $this->_objectManager->create($this->_instanceName, $data);
+ return $this->objectManager->create($this->instanceName, $data);
}
}
diff --git a/lib/internal/Magento/Framework/composer.json b/lib/internal/Magento/Framework/composer.json
index ed7e9f1cd1a1..c42323a2ecc0 100644
--- a/lib/internal/Magento/Framework/composer.json
+++ b/lib/internal/Magento/Framework/composer.json
@@ -37,6 +37,8 @@
"zendframework/zend-stdlib": "^3.2.1",
"zendframework/zend-uri": "^2.5.1",
"zendframework/zend-validator": "^2.6.0",
+ "zendframework/zend-mail": "^2.9.0",
+ "zendframework/zend-mime": "^2.5.0",
"guzzlehttp/guzzle": "^6.3.3"
},
"archive": {