11<?php
22/**
3- * Copyright © Magento, Inc. All rights reserved.
4- * See COPYING.txt for license details .
3+ * Copyright 2015 Adobe
4+ * All Rights Reserved .
55 */
66declare (strict_types=1 );
77
88namespace Magento \Email \Model ;
99
10- use Laminas \Mail \Transport \Smtp ;
11- use Laminas \Mail \Transport \SmtpOptions ;
10+ use Magento \Framework \Mail \EmailMessageInterface ;
11+ use Symfony \Component \Mailer \Exception \TransportExceptionInterface ;
12+ use Symfony \Component \Mailer \Mailer ;
13+ use Symfony \Component \Mailer \Transport \NativeTransportFactory ;
14+ use Symfony \Component \Mailer \Transport \Dsn ;
15+ use Symfony \Component \Mailer \Transport \TransportInterface as SymfonyTransportInterface ;
16+ use Symfony \Component \Mailer \Transport \Smtp \EsmtpTransport ;
17+ use Symfony \Component \Mailer \Transport \Smtp \Auth \LoginAuthenticator ;
18+ use Symfony \Component \Mailer \Transport \Smtp \Auth \PlainAuthenticator ;
1219use Magento \Framework \App \Config \ScopeConfigInterface ;
1320use Magento \Framework \App \ObjectManager ;
1421use Magento \Framework \Exception \MailException ;
15- use Magento \Framework \Mail \MessageInterface ;
1622use Magento \Framework \Mail \TransportInterface ;
1723use Magento \Framework \Phrase ;
24+ use Symfony \Component \Mime \Message as SymfonyMessage ;
1825use Magento \Store \Model \ScopeInterface ;
19- use Laminas \Mail \Message ;
20- use Laminas \Mail \Transport \Sendmail ;
21- use Laminas \Mail \Transport \TransportInterface as LaminasTransportInterface ;
2226use Psr \Log \LoggerInterface ;
2327
2428/**
2529 * Class that responsible for filling some message data before transporting it.
26- * @see \Laminas\Mail\Transport\Sendmail is used for transport
30+ * @see \Symfony\Component\Mailer\Transport is used for transport
2731 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
2832 */
2933class Transport implements TransportInterface
@@ -84,48 +88,41 @@ class Transport implements TransportInterface
8488 *
8589 * @var int
8690 */
87- private $ isSetReturnPath ;
91+ private int $ isSetReturnPath ;
8892
8993 /**
9094 * @var string|null
9195 */
92- private $ returnPathValue ;
96+ private ? string $ returnPathValue ;
9397
9498 /**
9599 * @var ScopeConfigInterface
96100 */
97- private $ scopeConfig ;
101+ private ScopeConfigInterface $ scopeConfig ;
98102
99103 /**
100- * @var LaminasTransportInterface|null
104+ * @var SymfonyTransportInterface
101105 */
102- private $ laminasTransport ;
106+ private SymfonyTransportInterface $ symfonyTransport ;
103107
104108 /**
105- * @var null|string|array|\Traversable
109+ * @var EmailMessageInterface
106110 */
107- private $ parameters ;
108-
109- /**
110- * @var MessageInterface
111- */
112- private $ message ;
111+ private EmailMessageInterface $ message ;
113112
114113 /**
115114 * @var LoggerInterface|null
116115 */
117- private $ logger ;
116+ private ? LoggerInterface $ logger ;
118117
119118 /**
120- * @param MessageInterface $message Email message object
119+ * @param EmailMessageInterface $message Email message object
121120 * @param ScopeConfigInterface $scopeConfig Core store config
122- * @param null|string|array|\Traversable $parameters Config options for sendmail parameters
123121 * @param LoggerInterface|null $logger
124122 */
125123 public function __construct (
126- MessageInterface $ message ,
124+ EmailMessageInterface $ message ,
127125 ScopeConfigInterface $ scopeConfig ,
128- $ parameters = null ,
129126 ?LoggerInterface $ logger = null
130127 ) {
131128 $ this ->isSetReturnPath = (int ) $ scopeConfig ->getValue (
@@ -138,131 +135,126 @@ public function __construct(
138135 );
139136 $ this ->message = $ message ;
140137 $ this ->scopeConfig = $ scopeConfig ;
141- $ this ->parameters = $ parameters ;
142138 $ this ->logger = $ logger ?: ObjectManager::getInstance ()->get (LoggerInterface::class);
143139 }
144140
145141 /**
146- * Get the LaminasTransport based on the configuration.
142+ * Get the SymfonyTransport based on the configuration.
147143 *
148- * @return LaminasTransportInterface
144+ * @return SymfonyTransportInterface
149145 */
150- public function getTransport (): LaminasTransportInterface
146+ public function getTransport (): SymfonyTransportInterface
151147 {
152- if ($ this ->laminasTransport === null ) {
153- $ transport = $ this ->scopeConfig ->getValue (
154- self ::XML_PATH_TRANSPORT ,
155- ScopeInterface::SCOPE_STORE
156- );
157-
158- if ($ transport === 'smtp ' ) {
159- $ this ->laminasTransport = $ this ->createSmtpTransport ();
148+ if (!isset ($ this ->symfonyTransport )) {
149+ $ transportType = $ this ->scopeConfig ->getValue (self ::XML_PATH_TRANSPORT );
150+ if ($ transportType === 'smtp ' ) {
151+ $ this ->symfonyTransport = $ this ->createSmtpTransport ();
160152 } else {
161- $ this ->laminasTransport = $ this ->createSendmailTransport ();
153+ $ this ->symfonyTransport = $ this ->createSendmailTransport ();
162154 }
163155 }
164156
165- return $ this ->laminasTransport ;
157+ return $ this ->symfonyTransport ;
166158 }
167159
168160 /**
169- * @inheritdoc
161+ * Build the DSN string for Symfony transport based on configuration.
162+ *
163+ * @return SymfonyTransportInterface
170164 */
171- public function sendMessage ()
165+ private function createSmtpTransport (): SymfonyTransportInterface
172166 {
173- try {
174- $ laminasMessage = Message::fromString ($ this ->message ->getRawMessage ())->setEncoding ('utf-8 ' );
175- if (2 === $ this ->isSetReturnPath && $ this ->returnPathValue ) {
176- $ laminasMessage ->setSender ($ this ->returnPathValue );
177- } elseif (1 === $ this ->isSetReturnPath && $ laminasMessage ->getFrom ()->count ()) {
178- $ fromAddressList = $ laminasMessage ->getFrom ();
179- $ fromAddressList ->rewind ();
180- $ laminasMessage ->setSender ($ fromAddressList ->current ()->getEmail ());
181- }
167+ $ host = $ this ->scopeConfig ->getValue (self ::XML_PATH_HOST , ScopeInterface::SCOPE_STORE );
168+ $ port = (int ) $ this ->scopeConfig ->getValue (self ::XML_PATH_PORT , ScopeInterface::SCOPE_STORE );
169+ $ username = $ this ->scopeConfig ->getValue (self ::XML_PATH_USERNAME , ScopeInterface::SCOPE_STORE );
170+ $ password = $ this ->scopeConfig ->getValue (self ::XML_PATH_PASSWORD , ScopeInterface::SCOPE_STORE );
171+ $ auth = $ this ->scopeConfig ->getValue (self ::XML_PATH_AUTH , ScopeInterface::SCOPE_STORE );
172+ $ ssl = $ this ->scopeConfig ->getValue (self ::XML_PATH_SSL , ScopeInterface::SCOPE_STORE );
173+ $ tls = false ;
174+
175+ if ($ ssl === 'tls ' ) {
176+ $ tls = true ;
177+ }
182178
183- $ this ->getTransport ()->send ($ laminasMessage );
184- } catch (\Exception $ e ) {
185- $ this ->logger ->error ($ e );
186- throw new MailException (new Phrase ('Unable to send mail. Please try again later. ' ), $ e );
179+ $ transport = new EsmtpTransport ($ host , $ port , $ tls );
180+ if ($ username ) {
181+ $ transport ->setUsername ($ username );
182+ }
183+ if ($ password ) {
184+ $ transport ->setPassword ($ password );
187185 }
186+
187+ switch ($ auth ) {
188+ case 'plain ' :
189+ $ transport ->setAuthenticators ([new PlainAuthenticator ()]);
190+ break ;
191+ case 'login ' :
192+ $ transport ->setAuthenticators ([new LoginAuthenticator ()]);
193+ break ;
194+ case 'none ' :
195+ break ;
196+ default :
197+ throw new \InvalidArgumentException ('Invalid authentication type: ' . $ auth );
198+ }
199+
200+ return $ transport ;
188201 }
189202
190203 /**
191- * @inheritdoc
204+ * Create a Sendmail transport for Symfony Mailer.
205+ *
206+ * @return SymfonyTransportInterface
192207 */
193- public function getMessage ()
208+ private function createSendmailTransport (): SymfonyTransportInterface
194209 {
195- return $ this ->message ;
210+ $ dsn = new Dsn ('native ' , 'default ' );
211+ $ nativeTransportFactory = new NativeTransportFactory ();
212+ return $ nativeTransportFactory ->create ($ dsn );
196213 }
197214
198215 /**
199- * Create a Smtp LaminasTransport.
200- *
201- * @return Smtp
216+ * @inheritdoc
202217 */
203- private function createSmtpTransport (): Smtp
218+ public function sendMessage (): void
204219 {
205- $ host = $ this ->scopeConfig ->getValue (
206- self ::XML_PATH_HOST ,
207- ScopeInterface::SCOPE_STORE
208- );
209-
210- $ port = $ this ->scopeConfig ->getValue (
211- self ::XML_PATH_PORT ,
212- ScopeInterface::SCOPE_STORE
213- );
214-
215- $ username = $ this ->scopeConfig ->getValue (
216- self ::XML_PATH_USERNAME ,
217- ScopeInterface::SCOPE_STORE
218- );
219-
220- $ password = $ this ->scopeConfig ->getValue (
221- self ::XML_PATH_PASSWORD ,
222- ScopeInterface::SCOPE_STORE
223- );
224-
225- $ auth = $ this ->scopeConfig ->getValue (
226- self ::XML_PATH_AUTH ,
227- ScopeInterface::SCOPE_STORE
228- );
229-
230- $ ssl = $ this ->scopeConfig ->getValue (
231- self ::XML_PATH_SSL ,
232- ScopeInterface::SCOPE_STORE
233- );
234-
235- $ options = [
236- 'name ' => 'localhost ' ,
237- 'host ' => $ host ,
238- 'port ' => $ port ,
239- 'connection_config ' => [
240- 'username ' => $ username ,
241- 'password ' => $ password ,
242- ]
243- ];
244-
245- if ($ auth && $ auth !== 'none ' ) {
246- $ options ['connection_class ' ] = $ auth ;
220+ try {
221+ $ email = $ this ->message ->getSymfonyMessage ();
222+ $ this ->setReturnPath ($ email );
223+ $ mailer = new Mailer ($ this ->getTransport ());
224+ $ mailer ->send ($ email );
225+ } catch (TransportExceptionInterface $ transportException ) {
226+ $ this ->logger ->error ('Transport error while sending email: ' . $ transportException ->getMessage ());
227+ throw new MailException (
228+ new Phrase ('Transport error: Unable to send mail at this time. ' ),
229+ $ transportException
230+ );
231+ } catch (\Exception $ e ) {
232+ $ this ->logger ->error ($ e );
233+ throw new MailException (new Phrase ('Unable to send mail. Please try again later. ' ), $ e );
247234 }
235+ }
248236
249- if ($ ssl && $ ssl !== 'none ' ) {
250- $ options ['connection_config ' ]['ssl ' ] = $ ssl ;
237+ /**
238+ * Set the return path if configured.
239+ *
240+ * @param SymfonyMessage $email
241+ */
242+ private function setReturnPath (SymfonyMessage $ email ): void
243+ {
244+ if ($ this ->isSetReturnPath === 2 && $ this ->returnPathValue ) {
245+ $ email ->getHeaders ()->addMailboxListHeader ('Sender ' , [$ this ->returnPathValue ]);
246+ } elseif ($ this ->isSetReturnPath === 1 &&
247+ !empty ($ fromAddresses = $ email ->getHeaders ()->get ('From ' )?->getAddresses())) {
248+ reset ($ fromAddresses );
249+ $ email ->getHeaders ()->addMailboxListHeader ('Sender ' , [current ($ fromAddresses )->getAddress ()]);
251250 }
252-
253- $ transport = new Smtp ();
254- $ transport ->setOptions (new SmtpOptions ($ options ));
255-
256- return $ transport ;
257251 }
258252
259253 /**
260- * Create a Sendmail Laminas Transport
261- *
262- * @return Sendmail
254+ * @inheritdoc
263255 */
264- private function createSendmailTransport (): Sendmail
256+ public function getMessage (): EmailMessageInterface
265257 {
266- return new Sendmail ( $ this ->parameters ) ;
258+ return $ this ->message ;
267259 }
268260}
0 commit comments