e2f2776638cb945c68e8166695218aa861e572f6
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Classes / Mail / MailMessage.php
1 <?php
2 namespace TYPO3\CMS\Core\Mail;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 /**
18 * Adapter for Swift_Mailer to be used by TYPO3 extensions
19 */
20 class MailMessage extends \Swift_Message
21 {
22 /**
23 * @var \TYPO3\CMS\Core\Mail\Mailer
24 */
25 protected $mailer;
26
27 /**
28 * @var string This will be added as X-Mailer to all outgoing mails
29 */
30 protected $mailerHeader = 'TYPO3';
31
32 /**
33 * TRUE if the message has been sent.
34 *
35 * @var bool
36 */
37 protected $sent = false;
38
39 /**
40 * Holds the failed recipients after the message has been sent
41 *
42 * @var array
43 */
44 protected $failedRecipients = [];
45
46 /**
47 * @return void
48 */
49 private function initializeMailer()
50 {
51 $this->mailer = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\Mail\Mailer::class);
52 }
53
54 /**
55 * Sends the message.
56 *
57 * @return int the number of recipients who were accepted for delivery
58 */
59 public function send()
60 {
61 $this->initializeMailer();
62 $this->sent = true;
63 $this->getHeaders()->addTextHeader('X-Mailer', $this->mailerHeader);
64 return $this->mailer->send($this, $this->failedRecipients);
65 }
66
67 /**
68 * Checks whether the message has been sent.
69 *
70 * @return bool
71 */
72 public function isSent()
73 {
74 return $this->sent;
75 }
76
77 /**
78 * Returns the recipients for which the mail was not accepted for delivery.
79 *
80 * @return array the recipients who were not accepted for delivery
81 */
82 public function getFailedRecipients()
83 {
84 return $this->failedRecipients;
85 }
86
87 /**
88 * Set the return-path (the bounce address) of this message.
89 *
90 * @param string $address
91 * @return \TYPO3\CMS\Core\Mail\MailMessage
92 */
93 public function setReturnPath($address)
94 {
95 $address = $this->idnaEncodeAddresses($address);
96 return parent::setReturnPath($address);
97 }
98
99 /**
100 * Set the sender of this message.
101 *
102 * This does not override the From field, but it has a higher significance.
103 *
104 * @param string $address
105 * @param string $name optional
106 * @return \TYPO3\CMS\Core\Mail\MailMessage
107 */
108 public function setSender($address, $name = null)
109 {
110 $address = $this->idnaEncodeAddresses($address);
111 return parent::setSender($address, $name);
112 }
113
114 /**
115 * Set the from address of this message.
116 *
117 * You may pass an array of addresses if this message is from multiple people.
118 *
119 * If $name is passed and the first parameter is a string, this name will be
120 * associated with the address.
121 *
122 * @param string|array $addresses
123 * @param string $name optional
124 * @return \TYPO3\CMS\Core\Mail\MailMessage
125 */
126 public function setFrom($addresses, $name = null)
127 {
128 $addresses = $this->idnaEncodeAddresses($addresses);
129 return parent::setFrom($addresses, $name);
130 }
131
132 /**
133 * Set the reply-to address of this message.
134 *
135 * You may pass an array of addresses if replies will go to multiple people.
136 *
137 * If $name is passed and the first parameter is a string, this name will be
138 * associated with the address.
139 *
140 * @param string|array $addresses
141 * @param string $name optional
142 * @return \TYPO3\CMS\Core\Mail\MailMessage
143 */
144 public function setReplyTo($addresses, $name = null)
145 {
146 $addresses = $this->idnaEncodeAddresses($addresses);
147 return parent::setReplyTo($addresses, $name);
148 }
149
150 /**
151 * Set the to addresses of this message.
152 *
153 * If multiple recipients will receive the message an array should be used.
154 * Example: array('receiver@domain.org', 'other@domain.org' => 'A name')
155 *
156 * If $name is passed and the first parameter is a string, this name will be
157 * associated with the address.
158 *
159 * @param string|array $addresses
160 * @param string $name optional
161 * @return \TYPO3\CMS\Core\Mail\MailMessage
162 */
163 public function setTo($addresses, $name = null)
164 {
165 $addresses = $this->idnaEncodeAddresses($addresses);
166 return parent::setTo($addresses, $name);
167 }
168
169 /**
170 * Set the Cc addresses of this message.
171 *
172 * If $name is passed and the first parameter is a string, this name will be
173 * associated with the address.
174 *
175 * @param string|array $addresses
176 * @param string $name optional
177 * @return \TYPO3\CMS\Core\Mail\MailMessage
178 */
179 public function setCc($addresses, $name = null)
180 {
181 $addresses = $this->idnaEncodeAddresses($addresses);
182 return parent::setCc($addresses, $name);
183 }
184
185 /**
186 * Set the Bcc addresses of this message.
187 *
188 * If $name is passed and the first parameter is a string, this name will be
189 * associated with the address.
190 *
191 * @param string|array $addresses
192 * @param string $name optional
193 * @return \TYPO3\CMS\Core\Mail\MailMessage
194 */
195 public function setBcc($addresses, $name = null)
196 {
197 $addresses = $this->idnaEncodeAddresses($addresses);
198 return parent::setBcc($addresses, $name);
199 }
200
201 /**
202 * Ask for a delivery receipt from the recipient to be sent to $addresses.
203 *
204 * @param array $addresses
205 * @return \TYPO3\CMS\Core\Mail\MailMessage
206 */
207 public function setReadReceiptTo($addresses)
208 {
209 $addresses = $this->idnaEncodeAddresses($addresses);
210 return parent::setReadReceiptTo($addresses);
211 }
212
213 /**
214 * IDNA encode email addresses. Accepts addresses in all formats that SwiftMailer supports
215 *
216 * @param string|array $addresses
217 * @return string|array
218 */
219 protected function idnaEncodeAddresses($addresses)
220 {
221 if (!is_array($addresses)) {
222 return $this->idnaEncodeAddress($addresses);
223 }
224 $newAddresses = [];
225 foreach ($addresses as $email => $name) {
226 if (ctype_digit($email)) {
227 $newAddresses[] = $this->idnaEncodeAddress($name);
228 } else {
229 $newAddresses[$this->idnaEncodeAddress($email)] = $name;
230 }
231 }
232
233 return $newAddresses;
234 }
235
236 /**
237 * IDNA encode the domain part of an email address if it contains non ASCII characters
238 *
239 * @param mixed $email
240 * @return mixed
241 * @see \TYPO3\CMS\Core\Utility\GeneralUtility::validEmail
242 */
243 protected function idnaEncodeAddress($email)
244 {
245 // Early return in case input is not a string
246 if (!is_string($email)) {
247 return $email;
248 }
249 // Split on the last "@" since adresses like "foo@bar"@example.org are valid
250 $atPosition = strrpos($email, '@');
251 if (!$atPosition || $atPosition + 1 === strlen($email)) {
252 // Return if no @ found or it is placed at the very beginning or end of the email
253 return $email;
254 }
255 $domain = substr($email, $atPosition + 1);
256 $local = substr($email, 0, $atPosition);
257 $domain = \TYPO3\CMS\Core\Utility\GeneralUtility::idnaEncode($domain);
258
259 return $local . '@' . $domain;
260 }
261 }