1010use Neos \Flow \ResourceManagement \Exception as ResourceException ;
1111use Neos \Flow \ResourceManagement \PersistentResource ;
1212use Neos \Flow \ResourceManagement \ResourceManager ;
13- use Neos \SwiftMailer \Message ;
14- use Swift_Attachment ;
15- use Swift_Image ;
16- use Swift_Message ;
13+ use Neos \SymfonyMailer \Exception \InvalidMailerConfigurationException ;
14+ use Neos \SymfonyMailer \Service \MailerService ;
1715use Swisscom \CommunicationDispatcher \Domain \Model \Dto \Recipient ;
1816use Swisscom \CommunicationDispatcher \Exception ;
17+ use Symfony \Component \Mailer \Exception \TransportExceptionInterface ;
18+ use Symfony \Component \Mime \Address ;
19+ use Symfony \Component \Mime \Email ;
1920
2021/**
2122 * @Flow\Scope("prototype")
2223 */
2324class EmailChannel implements ChannelInterface
2425{
26+ /**
27+ * @Flow\Inject
28+ * @var MailerService
29+ */
30+ protected $ mailerService ;
2531
2632 /**
2733 * @Flow\Inject
@@ -30,17 +36,17 @@ class EmailChannel implements ChannelInterface
3036 protected $ resourceManager ;
3137
3238 /**
33- * @var string
39+ * @var array< string, string>
3440 */
3541 protected $ from ;
3642
3743 /**
38- * @var string
44+ * @var array< string, string>
3945 */
4046 protected $ replyTo ;
4147
4248 /**
43- * @var string
49+ * @var array< string, string>
4450 */
4551 protected $ cc ;
4652
@@ -49,9 +55,9 @@ class EmailChannel implements ChannelInterface
4955 */
5056 function __construct (array $ options = [])
5157 {
52- $ this ->from = isset ( $ options ['from ' ]) ? $ options [ ' from ' ] : '' ;
53- $ this ->replyTo = isset ( $ options ['replyTo ' ]) ? $ options [ ' replyTo ' ] : '' ;
54- $ this ->cc = isset ( $ options ['cc ' ]) ? $ options [ ' cc ' ] : '' ;
58+ $ this ->from = $ options ['from ' ] ?? '' ;
59+ $ this ->replyTo = $ options ['replyTo ' ] ?? '' ;
60+ $ this ->cc = $ options ['cc ' ] ?? '' ;
5561 }
5662
5763 /**
@@ -61,105 +67,54 @@ function __construct(array $options = [])
6167 * @param array $options
6268 * @return void
6369 * @throws Exception
70+ * @throws ResourceException
71+ * @throws InvalidMailerConfigurationException
72+ * @throws TransportExceptionInterface
6473 */
6574 public function send (Recipient $ recipient , string $ subject , string $ text , array $ options = [])
6675 {
6776 $ toEmail = $ recipient ->getEmail ();
6877 $ toName = $ recipient ->getName ();
69- $ attachedResources = $ options ['attachedResources ' ] ?? [];
78+ $ attachedResources = isset ($ options ['attachedResources ' ]) && is_array ($ options ['attachedResources ' ])
79+ ? $ options ['attachedResources ' ]
80+ : [];
7081
7182 if (empty ($ toEmail )) {
7283 throw new Exception ('Recipient has no email address ' , 1570541186 );
7384 }
74- $ mail = new Message ();
75- $ mail ->setFrom ($ this ->from );
85+
86+ $ email = new Email ();
87+ $ email
88+ ->from ($ this ->arrayToAddress ($ this ->from ))
89+ ->subject ($ subject );
90+
7691 if (!empty ($ this ->replyTo )) {
77- $ mail -> setReplyTo ($ this ->replyTo );
92+ $ email -> replyTo ($ this ->arrayToAddress ( $ this -> replyTo ) );
7893 }
79- $ mail -> setTo ( $ toEmail , $ toName );
94+ $ email -> to ( new Address ( $ toEmail , $ toName) );
8095 if (!empty ($ this ->cc )) {
81- $ mail -> setCc ($ this ->cc );
96+ $ email -> cc ($ this ->arrayToAddress ( $ this -> cc ) );
8297 }
83- $ mail ->setSubject (htmlspecialchars_decode ($ subject ));
84- $ plaintext = preg_replace (array ('/\s{2,}/ ' , '/[\t]/ ' , '/###IMAGE:(.+?)###/ ' , '/###PLAIN:(.+?)###/ ' ), ' ' , strip_tags ($ text ));
85- $ text = $ this ->embedResources ($ text , $ mail );
98+ $ email ->subject (htmlspecialchars_decode ($ subject ));
99+
100+ $ html = $ this ->formatInternetMessage ($ text );
101+ $ text = $ this ->formatInternetMessage (strip_tags ($ text ));
86102
87- $ text = $ this -> formatInternetMessage ( $ text );
88- $ plaintext = $ this -> formatInternetMessage ( $ plaintext );
103+ $ email -> html ( $ html );
104+ $ email -> text ( $ text );
89105
90- $ mail ->setBody ($ text , 'text/html ' , 'utf-8 ' );
91- $ mail ->addPart ($ plaintext , 'text/plain ' , 'utf-8 ' );
92- foreach ($ attachedResources as $ resource ) {
106+ foreach ($ attachedResources as $ name => $ resource ) {
93107 if ($ resource instanceof PersistentResource) {
94- if ($ swiftAttachment = $ this ->createSwiftAttachmentFromPersistentResource ($ resource )) {
95- $ mail -> attach ( $ swiftAttachment );
108+ if ($ path = $ this ->getPathFromPersistentResource ($ resource )) {
109+ $ email -> attachFromPath ( $ path , $ resource -> getFilename (), $ resource -> getMediaType () );
96110 }
97- } elseif ($ resource instanceof Swift_Attachment ) {
98- $ mail ->attach ($ resource );
111+ } elseif (is_string ( $ resource) && is_string ( $ name ) ) {
112+ $ email ->attach ($ resource, $ name , ' text/plain ' );
99113 }
100114 }
101115
102- $ acceptedRecipients = $ mail ->send ();
103- if ($ acceptedRecipients <= 0 ) {
104- throw new Exception ('Sending SwiftMessage failed ' , 1570541189 );
105- }
106- }
107-
108- /**
109- * Embed images. I.e:
110- * <img height="40px" src="###IMAGE:'{template.logo}'###" alt="Logo"/>
111- *
112- * @param string $html
113- * @param Swift_Message $mail
114- * @return string $html
115- */
116- private function embedResources (string $ html , Swift_Message &$ mail ): string
117- {
118- $ html = preg_replace_callback ('/###IMAGE:(.+?)###/ ' , function ($ matches ) use ($ mail ) {
119- return $ this ->embedImageResourceCallback ($ matches , $ mail );
120- }, $ html );
121- $ html = preg_replace_callback ('/###PLAIN:(.+?)###/ ' , function ($ matches ) use ($ mail ) {
122- return $ this ->embedPlainResourceCallback ($ matches );
123- }, $ html );
124-
125- return $ html ;
126- }
127-
128- /**
129- * @param array $matches
130- * @param \Swift_Message $mail
131- * @return string
132- */
133- private function embedImageResourceCallback (array $ matches , Swift_Message &$ mail ): string
134- {
135- $ cid = '' ;
136- if (isset ($ matches [1 ])) {
137- $ source = trim ($ matches [1 ], '\'' );
138- try {
139- $ cid = $ mail ->embed (Swift_Image::fromPath ($ source ));
140- } catch (\Exception $ e ) {
141- // Nothing to do here
142- }
143- }
144- return $ cid ;
145- }
146-
147- /**
148- * @param array $matches
149- * @return string
150- */
151- private function embedPlainResourceCallback (array $ matches ): string
152- {
153- $ plain = '' ;
154- if (isset ($ matches [1 ])) {
155- $ source = trim ($ matches [1 ], '\'' );
156- try {
157- $ plain = file_get_contents ($ source );
158- } catch (\Exception $ e ) {
159- // Nothing to do here
160- }
161- }
162- return $ plain ;
116+ $ mailer = $ this ->mailerService ->getMailer ();
117+ $ mailer ->send ($ email );
163118 }
164119
165120 /**
@@ -180,18 +135,24 @@ private function formatInternetMessage(string $text): string
180135 return implode (PHP_EOL , $ lines );
181136 }
182137
183- public function createSwiftAttachmentFromPersistentResource (PersistentResource $ resource ): ?Swift_Attachment
138+ public function getPathFromPersistentResource (PersistentResource $ resource ): ?string
184139 {
185140 if (!is_string ($ resource ->getSha1 ())) {
186141 // Throw exception to prevent type error on getCacheEntryIdentifier(): "Return value must be of type string, null returned"
187142 throw new ResourceException ('No sha1 set in persistent resource ' , 1733826832 );
188143 }
189144
190145 // No exception handling here. This provides flexibility to handle it outside or by aspects
191- $ path = $ resource ->createTemporaryLocalCopy ();
192- $ attachment = Swift_Attachment::fromPath ($ path , $ resource ->getMediaType ());
193- $ attachment ->setFilename ($ resource ->getFilename ());
146+ return $ resource ->createTemporaryLocalCopy ();
147+ }
148+
149+ /**
150+ * @param array<string, string> $array
151+ */
152+ protected function arrayToAddress (array $ array ): Address
153+ {
154+ $ email = (string )array_key_first ($ array );
194155
195- return $ attachment ;
156+ return new Address ( $ email , $ array [ $ email ]) ;
196157 }
197158}
0 commit comments