Passed
Push — master ( fc4e87...bbd3e2 )
by Blizzz
17:23 queued 18s
created

Message::convertAddresses()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 16
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 9
nc 2
nop 1
dl 0
loc 16
rs 9.9666
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * @copyright Copyright (c) 2016, ownCloud, Inc.
7
 *
8
 * @author Arne Hamann <[email protected]>
9
 * @author Christoph Wurst <[email protected]>
10
 * @author Jared Boone <[email protected]>
11
 * @author Joas Schilling <[email protected]>
12
 * @author Lukas Reschke <[email protected]>
13
 * @author Morris Jobke <[email protected]>
14
 * @author Roeland Jago Douma <[email protected]>
15
 * @author Thomas Müller <[email protected]>
16
 *
17
 * @license AGPL-3.0
18
 *
19
 * This code is free software: you can redistribute it and/or modify
20
 * it under the terms of the GNU Affero General Public License, version 3,
21
 * as published by the Free Software Foundation.
22
 *
23
 * This program is distributed in the hope that it will be useful,
24
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26
 * GNU Affero General Public License for more details.
27
 *
28
 * You should have received a copy of the GNU Affero General Public License, version 3,
29
 * along with this program. If not, see <http://www.gnu.org/licenses/>
30
 *
31
 */
32
namespace OC\Mail;
33
34
use OCP\Mail\Headers\AutoSubmitted;
35
use OCP\Mail\IAttachment;
36
use OCP\Mail\IEMailTemplate;
37
use OCP\Mail\IMessage;
38
use Symfony\Component\Mime\Address;
39
use Symfony\Component\Mime\Email;
40
use Symfony\Component\Mime\Exception\InvalidArgumentException;
41
use Symfony\Component\Mime\Exception\RfcComplianceException;
42
43
/**
44
 * Class Message provides a wrapper around Symfony\Component\Mime\Email (Used to be around SwiftMail)
45
 *
46
 * @package OC\Mail
47
 */
48
class Message implements IMessage {
49
	private Email $symfonyEmail;
50
	private bool $plainTextOnly;
51
52
	private array $to;
53
	private array $from;
54
	private array $replyTo;
55
	private array $cc;
56
	private array $bcc;
57
58
	public function __construct(Email $symfonyEmail, bool $plainTextOnly) {
59
		$this->symfonyEmail = $symfonyEmail;
60
		$this->plainTextOnly = $plainTextOnly;
61
		$this->to = [];
62
		$this->from = [];
63
		$this->replyTo = [];
64
		$this->cc = [];
65
		$this->bcc = [];
66
	}
67
68
	/**
69
	 * @return $this
70
	 * @since 13.0.0
71
	 */
72
	public function attach(IAttachment $attachment): IMessage {
73
		/** @var Attachment $attachment */
74
		$attachment->attach($this->symfonyEmail);
75
		return $this;
76
	}
77
78
	/**
79
	 * Converts the [['displayName' => 'email'], ['displayName2' => 'email2']] arrays to valid Adresses
80
	 *
81
	 * @param array $addresses Array of mail addresses
82
	 * @return Address[]
83
	 * @throws RfcComplianceException|InvalidArgumentException
84
	 */
85
	protected function convertAddresses(array $addresses): array {
86
		$convertedAddresses = [];
87
88
		if (empty($addresses)) {
89
			return [];
90
		}
91
92
		array_walk($addresses, function ($readableName, $email) use (&$convertedAddresses) {
93
			if (is_numeric($email)) {
94
				$convertedAddresses[] = new Address($readableName);
95
			} else {
96
				$convertedAddresses[] = new Address($email, $readableName);
97
			}
98
		});
99
100
		return $convertedAddresses;
101
	}
102
103
	/**
104
	 * Set the from address of this message.
105
	 *
106
	 * If no "From" address is used \OC\Mail\Mailer will use mail_from_address and mail_domain from config.php
107
	 *
108
	 * @param array $addresses Example: array('[email protected]', '[email protected]' => 'A name')
109
	 * @return $this
110
	 */
111
	public function setFrom(array $addresses): IMessage {
112
		$this->from = $addresses;
113
		return $this;
114
	}
115
116
	/**
117
	 * Get the from address of this message.
118
	 */
119
	public function getFrom(): array {
120
		return $this->from;
121
	}
122
123
	/**
124
	 * Set the Reply-To address of this message
125
	 *
126
	 * @return $this
127
	 */
128
	public function setReplyTo(array $addresses): IMessage {
129
		$this->replyTo = $addresses;
130
		return $this;
131
	}
132
133
	/**
134
	 * Returns the Reply-To address of this message
135
	 */
136
	public function getReplyTo(): array {
137
		return $this->replyTo;
138
	}
139
140
	/**
141
	 * Set the to addresses of this message.
142
	 *
143
	 * @param array $recipients Example: array('[email protected]', '[email protected]' => 'A name')
144
	 * @return $this
145
	 */
146
	public function setTo(array $recipients): IMessage {
147
		$this->to = $recipients;
148
		return $this;
149
	}
150
151
	/**
152
	 * Get the to address of this message.
153
	 */
154
	public function getTo(): array {
155
		return $this->to;
156
	}
157
158
	/**
159
	 * Set the CC recipients of this message.
160
	 *
161
	 * @param array $recipients Example: array('[email protected]', '[email protected]' => 'A name')
162
	 * @return $this
163
	 */
164
	public function setCc(array $recipients): IMessage {
165
		$this->cc = $recipients;
166
		return $this;
167
	}
168
169
	/**
170
	 * Get the cc address of this message.
171
	 */
172
	public function getCc(): array {
173
		return $this->cc;
174
	}
175
176
	/**
177
	 * Set the BCC recipients of this message.
178
	 *
179
	 * @param array $recipients Example: array('[email protected]', '[email protected]' => 'A name')
180
	 * @return $this
181
	 */
182
	public function setBcc(array $recipients): IMessage {
183
		$this->bcc = $recipients;
184
		return $this;
185
	}
186
187
	/**
188
	 * Get the Bcc address of this message.
189
	 */
190
	public function getBcc(): array {
191
		return $this->bcc;
192
	}
193
194
	/**
195
	 * Set the subject of this message.
196
	 *
197
	 * @return $this
198
	 */
199
	public function setSubject(string $subject): IMessage {
200
		$this->symfonyEmail->subject($subject);
201
		return $this;
202
	}
203
204
	/**
205
	 * Get the from subject of this message.
206
	 */
207
	public function getSubject(): string {
208
		return $this->symfonyEmail->getSubject() ?? '';
209
	}
210
211
	/**
212
	 * Set the plain-text body of this message.
213
	 * @return $this
214
	 */
215
	public function setPlainBody(string $body): IMessage {
216
		$this->symfonyEmail->text($body);
217
		return $this;
218
	}
219
220
	/**
221
	 * Get the plain body of this message.
222
	 */
223
	public function getPlainBody(): string {
224
		/** @var string $body */
225
		$body = $this->symfonyEmail->getTextBody() ?? '';
226
		return $body;
227
	}
228
229
	/**
230
	 * Set the HTML body of this message. Consider also sending a plain-text body instead of only an HTML one.
231
	 * @return $this
232
	 */
233
	public function setHtmlBody(string $body): IMessage {
234
		if (!$this->plainTextOnly) {
235
			$this->symfonyEmail->html($body);
236
		}
237
		return $this;
238
	}
239
240
	/**
241
	 * Set the underlying Email intance
242
	 */
243
	public function setSymfonyEmail(Email $symfonyEmail): void {
244
		$this->symfonyEmail = $symfonyEmail;
245
	}
246
247
	/**
248
	 * Get the underlying Email instance
249
	 */
250
	public function getSymfonyEmail(): Email {
251
		return $this->symfonyEmail;
252
	}
253
254
	/**
255
	 * @return $this
256
	 */
257
	public function setBody(string $body, string $contentType): IMessage {
258
		if (!$this->plainTextOnly || $contentType !== 'text/html') {
259
			if ($contentType === 'text/html') {
260
				$this->symfonyEmail->html($body);
261
			} else {
262
				$this->symfonyEmail->text($body);
263
			}
264
		}
265
		return $this;
266
	}
267
268
	/**
269
	 * Set the recipients on the symphony email
270
	 *
271
	 * Since
272
	 *
273
	 * setTo
274
	 * setFrom
275
	 * setReplyTo
276
	 * setCc
277
	 * setBcc
278
	 *
279
	 * could throw a \Symfony\Component\Mime\Exception\RfcComplianceException
280
	 * or a \Symfony\Component\Mime\Exception\InvalidArgumentException
281
	 * we wrap the calls here. We then have the validation errors all in one place and can
282
	 * throw shortly before \OC\Mail\Mailer::send
283
	 *
284
	 * @return void
285
	 * @throws InvalidArgumentException|RfcComplianceException
286
	 */
287
	public function setRecipients() {
288
		$this->symfonyEmail->to(...$this->convertAddresses($this->getTo()));
289
		$this->symfonyEmail->from(...$this->convertAddresses($this->getFrom()));
290
		$this->symfonyEmail->replyTo(...$this->convertAddresses($this->getReplyTo()));
291
		$this->symfonyEmail->cc(...$this->convertAddresses($this->getCc()));
292
		$this->symfonyEmail->bcc(...$this->convertAddresses($this->getBcc()));
293
	}
294
295
	/**
296
	 * @return $this
297
	 */
298
	public function useTemplate(IEMailTemplate $emailTemplate): IMessage {
299
		$this->setSubject($emailTemplate->renderSubject());
300
		$this->setPlainBody($emailTemplate->renderText());
301
		if (!$this->plainTextOnly) {
302
			$this->setHtmlBody($emailTemplate->renderHtml());
303
		}
304
		return $this;
305
	}
306
307
	/**
308
	 * Add the Auto-Submitted header to the email, preventing most automated
309
	 * responses to automated messages.
310
	 *
311
	 * @param AutoSubmitted::VALUE_* $value (one of AutoSubmitted::VALUE_NO, AutoSubmitted::VALUE_AUTO_GENERATED, AutoSubmitted::VALUE_AUTO_REPLIED)
312
	 * @return $this
313
	 */
314
	public function setAutoSubmitted(string $value): IMessage {
315
		$headers = $this->symfonyEmail->getHeaders();
316
317
		if ($headers->has(AutoSubmitted::HEADER)) {
318
			// if the header already exsists, remove it.
319
			// the value can be modified with some implementations
320
			// of the interface \Swift_Mime_Header, however the
321
			// interface doesn't, and this makes the static-code
322
			// analysis unhappy.
323
			// @todo check if symfony mailer can modify the autosubmitted header
324
			$headers->remove(AutoSubmitted::HEADER);
325
		}
326
327
		$headers->addTextHeader(AutoSubmitted::HEADER, $value);
328
329
		return $this;
330
	}
331
332
	/**
333
	 * Get the current value of the Auto-Submitted header. Defaults to "no"
334
	 * which is equivalent to the header not existing at all
335
	 *
336
	 * @return string
337
	 */
338
	public function getAutoSubmitted(): string {
339
		$headers = $this->symfonyEmail->getHeaders();
340
341
		return $headers->has(AutoSubmitted::HEADER) ?
342
			$headers->get(AutoSubmitted::HEADER)->getBodyAsString() : AutoSubmitted::VALUE_NO;
343
	}
344
}
345