Passed
Push — master ( 662ab9...745543 )
by Christoph
19:09 queued 12s
created

Mailer   A

Complexity

Total Complexity 33

Size/Duplication

Total Lines 265
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 109
dl 0
loc 265
rs 9.76
c 0
b 0
f 0
wmc 33

11 Methods

Rating   Name   Duplication   Size   Complexity  
A createAttachment() 0 2 1
A send() 0 30 5
A __construct() 0 14 1
A createAttachmentFromPath() 0 2 1
A createMessage() 0 3 1
A createEMailTemplate() 0 19 4
A validateMailAddress() 0 9 2
A convertEmail() 0 8 4
A getInstance() 0 18 4
A getSendMailInstance() 0 24 4
B getSmtpInstance() 0 29 6
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 Branko Kokanovic <[email protected]>
10
 * @author Carsten Wiedmann <[email protected]>
11
 * @author Christoph Wurst <[email protected]>
12
 * @author Jared Boone <[email protected]>
13
 * @author Joas Schilling <[email protected]>
14
 * @author Julius Härtl <[email protected]>
15
 * @author kevin147147 <[email protected]>
16
 * @author Lukas Reschke <[email protected]>
17
 * @author Morris Jobke <[email protected]>
18
 * @author Roeland Jago Douma <[email protected]>
19
 * @author Tekhnee <[email protected]>
20
 *
21
 * @license AGPL-3.0
22
 *
23
 * This code is free software: you can redistribute it and/or modify
24
 * it under the terms of the GNU Affero General Public License, version 3,
25
 * as published by the Free Software Foundation.
26
 *
27
 * This program is distributed in the hope that it will be useful,
28
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
29
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30
 * GNU Affero General Public License for more details.
31
 *
32
 * You should have received a copy of the GNU Affero General Public License, version 3,
33
 * along with this program. If not, see <http://www.gnu.org/licenses/>
34
 *
35
 */
36
namespace OC\Mail;
37
38
use Egulias\EmailValidator\EmailValidator;
39
use Egulias\EmailValidator\Validation\RFCValidation;
40
use OCP\Defaults;
41
use OCP\EventDispatcher\IEventDispatcher;
42
use OCP\IConfig;
43
use OCP\IL10N;
44
use OCP\ILogger;
45
use OCP\IURLGenerator;
46
use OCP\L10N\IFactory;
47
use OCP\Mail\Events\BeforeMessageSent;
48
use OCP\Mail\IAttachment;
49
use OCP\Mail\IEMailTemplate;
50
use OCP\Mail\IMailer;
51
use OCP\Mail\IMessage;
52
53
/**
54
 * Class Mailer provides some basic functions to create a mail message that can be used in combination with
55
 * \OC\Mail\Message.
56
 *
57
 * Example usage:
58
 *
59
 * 	$mailer = \OC::$server->getMailer();
60
 * 	$message = $mailer->createMessage();
61
 * 	$message->setSubject('Your Subject');
62
 * 	$message->setFrom(array('[email protected]' => 'ownCloud Notifier'));
63
 * 	$message->setTo(array('[email protected]' => 'Recipient'));
64
 * 	$message->setBody('The message text', 'text/html');
65
 * 	$mailer->send($message);
66
 *
67
 * This message can then be passed to send() of \OC\Mail\Mailer
68
 *
69
 * @package OC\Mail
70
 */
71
class Mailer implements IMailer {
72
	/** @var \Swift_Mailer Cached mailer */
0 ignored issues
show
Bug introduced by
The type Swift_Mailer was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
73
	private $instance = null;
74
	/** @var IConfig */
75
	private $config;
76
	/** @var ILogger */
77
	private $logger;
78
	/** @var Defaults */
79
	private $defaults;
80
	/** @var IURLGenerator */
81
	private $urlGenerator;
82
	/** @var IL10N */
83
	private $l10n;
84
	/** @var IEventDispatcher */
85
	private $dispatcher;
86
	/** @var IFactory */
87
	private $l10nFactory;
88
89
	/**
90
	 * @param IConfig $config
91
	 * @param ILogger $logger
92
	 * @param Defaults $defaults
93
	 * @param IURLGenerator $urlGenerator
94
	 * @param IL10N $l10n
95
	 * @param IEventDispatcher $dispatcher
96
	 */
97
	public function __construct(IConfig $config,
98
						 ILogger $logger,
99
						 Defaults $defaults,
100
						 IURLGenerator $urlGenerator,
101
						 IL10N $l10n,
102
						 IEventDispatcher $dispatcher,
103
						 IFactory $l10nFactory) {
104
		$this->config = $config;
105
		$this->logger = $logger;
106
		$this->defaults = $defaults;
107
		$this->urlGenerator = $urlGenerator;
108
		$this->l10n = $l10n;
109
		$this->dispatcher = $dispatcher;
110
		$this->l10nFactory = $l10nFactory;
111
	}
112
113
	/**
114
	 * Creates a new message object that can be passed to send()
115
	 *
116
	 * @return IMessage
117
	 */
118
	public function createMessage(): IMessage {
119
		$plainTextOnly = $this->config->getSystemValue('mail_send_plaintext_only', false);
120
		return new Message(new \Swift_Message(), $plainTextOnly);
0 ignored issues
show
Bug introduced by
The type Swift_Message was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
121
	}
122
123
	/**
124
	 * @param string|null $data
125
	 * @param string|null $filename
126
	 * @param string|null $contentType
127
	 * @return IAttachment
128
	 * @since 13.0.0
129
	 */
130
	public function createAttachment($data = null, $filename = null, $contentType = null): IAttachment {
131
		return new Attachment(new \Swift_Attachment($data, $filename, $contentType));
0 ignored issues
show
Bug introduced by
The type Swift_Attachment was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
132
	}
133
134
	/**
135
	 * @param string $path
136
	 * @param string|null $contentType
137
	 * @return IAttachment
138
	 * @since 13.0.0
139
	 */
140
	public function createAttachmentFromPath(string $path, $contentType = null): IAttachment {
141
		return new Attachment(\Swift_Attachment::fromPath($path, $contentType));
142
	}
143
144
	/**
145
	 * Creates a new email template object
146
	 *
147
	 * @param string $emailId
148
	 * @param array $data
149
	 * @return IEMailTemplate
150
	 * @since 12.0.0
151
	 */
152
	public function createEMailTemplate(string $emailId, array $data = []): IEMailTemplate {
153
		$class = $this->config->getSystemValue('mail_template_class', '');
154
155
		if ($class !== '' && class_exists($class) && is_a($class, EMailTemplate::class, true)) {
156
			return new $class(
157
				$this->defaults,
158
				$this->urlGenerator,
159
				$this->l10nFactory,
160
				$emailId,
161
				$data
162
			);
163
		}
164
165
		return new EMailTemplate(
166
			$this->defaults,
167
			$this->urlGenerator,
168
			$this->l10nFactory,
169
			$emailId,
170
			$data
171
		);
172
	}
173
174
	/**
175
	 * Send the specified message. Also sets the from address to the value defined in config.php
176
	 * if no-one has been passed.
177
	 *
178
	 * @param IMessage|Message $message Message to send
179
	 * @return string[] Array with failed recipients. Be aware that this depends on the used mail backend and
180
	 * therefore should be considered
181
	 * @throws \Exception In case it was not possible to send the message. (for example if an invalid mail address
182
	 * has been supplied.)
183
	 */
184
	public function send(IMessage $message): array {
185
		$debugMode = $this->config->getSystemValue('mail_smtpdebug', false);
186
187
		if (empty($message->getFrom())) {
0 ignored issues
show
Bug introduced by
The method getFrom() does not exist on OCP\Mail\IMessage. Since it exists in all sub-types, consider adding an abstract or default implementation to OCP\Mail\IMessage. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

187
		if (empty($message->/** @scrutinizer ignore-call */ getFrom())) {
Loading history...
188
			$message->setFrom([\OCP\Util::getDefaultEmailAddress('no-reply') => $this->defaults->getName()]);
189
		}
190
191
		$failedRecipients = [];
192
193
		$mailer = $this->getInstance();
194
195
		// Enable logger if debug mode is enabled
196
		if ($debugMode) {
197
			$mailLogger = new \Swift_Plugins_Loggers_ArrayLogger();
0 ignored issues
show
Bug introduced by
The type Swift_Plugins_Loggers_ArrayLogger was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
198
			$mailer->registerPlugin(new \Swift_Plugins_LoggerPlugin($mailLogger));
0 ignored issues
show
Bug introduced by
The type Swift_Plugins_LoggerPlugin was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
199
		}
200
201
202
		$this->dispatcher->dispatchTyped(new BeforeMessageSent($message));
203
204
		$mailer->send($message->getSwiftMessage(), $failedRecipients);
0 ignored issues
show
Bug introduced by
The method getSwiftMessage() does not exist on OCP\Mail\IMessage. Since it exists in all sub-types, consider adding an abstract or default implementation to OCP\Mail\IMessage. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

204
		$mailer->send($message->/** @scrutinizer ignore-call */ getSwiftMessage(), $failedRecipients);
Loading history...
205
206
		// Debugging logging
207
		$logMessage = sprintf('Sent mail to "%s" with subject "%s"', print_r($message->getTo(), true), $message->getSubject());
0 ignored issues
show
Bug introduced by
The method getSubject() does not exist on OCP\Mail\IMessage. Since it exists in all sub-types, consider adding an abstract or default implementation to OCP\Mail\IMessage. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

207
		$logMessage = sprintf('Sent mail to "%s" with subject "%s"', print_r($message->getTo(), true), $message->/** @scrutinizer ignore-call */ getSubject());
Loading history...
Bug introduced by
The method getTo() does not exist on OCP\Mail\IMessage. Since it exists in all sub-types, consider adding an abstract or default implementation to OCP\Mail\IMessage. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

207
		$logMessage = sprintf('Sent mail to "%s" with subject "%s"', print_r($message->/** @scrutinizer ignore-call */ getTo(), true), $message->getSubject());
Loading history...
208
		$this->logger->debug($logMessage, ['app' => 'core']);
209
		if ($debugMode && isset($mailLogger)) {
210
			$this->logger->debug($mailLogger->dump(), ['app' => 'core']);
211
		}
212
213
		return $failedRecipients;
214
	}
215
216
	/**
217
	 * Checks if an e-mail address is valid
218
	 *
219
	 * @param string $email Email address to be validated
220
	 * @return bool True if the mail address is valid, false otherwise
221
	 */
222
	public function validateMailAddress(string $email): bool {
223
		if ($email === '') {
224
			// Shortcut: empty addresses are never valid
225
			return false;
226
		}
227
		$validator = new EmailValidator();
228
		$validation = new RFCValidation();
229
230
		return $validator->isValid($this->convertEmail($email), $validation);
231
	}
232
233
	/**
234
	 * SwiftMailer does currently not work with IDN domains, this function therefore converts the domains
235
	 *
236
	 * FIXME: Remove this once SwiftMailer supports IDN
237
	 *
238
	 * @param string $email
239
	 * @return string Converted mail address if `idn_to_ascii` exists
240
	 */
241
	protected function convertEmail(string $email): string {
242
		if (!function_exists('idn_to_ascii') || !defined('INTL_IDNA_VARIANT_UTS46') || strpos($email, '@') === false) {
243
			return $email;
244
		}
245
246
		[$name, $domain] = explode('@', $email, 2);
247
		$domain = idn_to_ascii($domain, 0,INTL_IDNA_VARIANT_UTS46);
248
		return $name.'@'.$domain;
249
	}
250
251
	protected function getInstance(): \Swift_Mailer {
252
		if (!is_null($this->instance)) {
253
			return $this->instance;
254
		}
255
256
		$transport = null;
257
258
		switch ($this->config->getSystemValue('mail_smtpmode', 'smtp')) {
259
			case 'sendmail':
260
				$transport = $this->getSendMailInstance();
261
				break;
262
			case 'smtp':
263
			default:
264
				$transport = $this->getSmtpInstance();
265
				break;
266
		}
267
268
		return new \Swift_Mailer($transport);
269
	}
270
271
	/**
272
	 * Returns the SMTP transport
273
	 *
274
	 * @return \Swift_SmtpTransport
275
	 */
276
	protected function getSmtpInstance(): \Swift_SmtpTransport {
0 ignored issues
show
Bug introduced by
The type Swift_SmtpTransport was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
277
		$transport = new \Swift_SmtpTransport();
278
		$transport->setTimeout($this->config->getSystemValue('mail_smtptimeout', 10));
279
		$transport->setHost($this->config->getSystemValue('mail_smtphost', '127.0.0.1'));
280
		$transport->setPort($this->config->getSystemValue('mail_smtpport', 25));
281
		if ($this->config->getSystemValue('mail_smtpauth', false)) {
282
			$transport->setUsername($this->config->getSystemValue('mail_smtpname', ''));
283
			$transport->setPassword($this->config->getSystemValue('mail_smtppassword', ''));
284
			$transport->setAuthMode($this->config->getSystemValue('mail_smtpauthtype', 'LOGIN'));
285
		}
286
		$smtpSecurity = $this->config->getSystemValue('mail_smtpsecure', '');
287
		if (!empty($smtpSecurity)) {
288
			$transport->setEncryption($smtpSecurity);
289
		}
290
		$streamingOptions = $this->config->getSystemValue('mail_smtpstreamoptions', []);
291
		if (is_array($streamingOptions) && !empty($streamingOptions)) {
292
			$transport->setStreamOptions($streamingOptions);
293
		}
294
295
		$overwriteCliUrl = parse_url(
296
			$this->config->getSystemValueString('overwrite.cli.url', ''),
297
			PHP_URL_HOST
298
		);
299
300
		if (!empty($overwriteCliUrl)) {
301
			$transport->setLocalDomain($overwriteCliUrl);
302
		}
303
304
		return $transport;
305
	}
306
307
	/**
308
	 * Returns the sendmail transport
309
	 *
310
	 * @return \Swift_SendmailTransport
311
	 */
312
	protected function getSendMailInstance(): \Swift_SendmailTransport {
0 ignored issues
show
Bug introduced by
The type Swift_SendmailTransport was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
313
		switch ($this->config->getSystemValue('mail_smtpmode', 'smtp')) {
314
			case 'qmail':
315
				$binaryPath = '/var/qmail/bin/sendmail';
316
				break;
317
			default:
318
				$sendmail = \OC_Helper::findBinaryPath('sendmail');
319
				if ($sendmail === null) {
320
					$sendmail = '/usr/sbin/sendmail';
321
				}
322
				$binaryPath = $sendmail;
323
				break;
324
		}
325
326
		switch ($this->config->getSystemValue('mail_sendmailmode', 'smtp')) {
327
			case 'pipe':
328
				$binaryParam = ' -t';
329
				break;
330
			default:
331
				$binaryParam = ' -bs';
332
				break;
333
		}
334
335
		return new \Swift_SendmailTransport($binaryPath . $binaryParam);
336
	}
337
}
338