Completed
Push — master ( 8969e1...3ade34 )
by Joas
21:37
created

Mailer::getMailInstance()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
declare(strict_types=1);
3
/**
4
 * @copyright Copyright (c) 2016, ownCloud, Inc.
5
 *
6
 * @author Joas Schilling <[email protected]>
7
 * @author Lukas Reschke <[email protected]>
8
 * @author Morris Jobke <[email protected]>
9
 * @author Roeland Jago Douma <[email protected]>
10
 *
11
 * @license AGPL-3.0
12
 *
13
 * This code is free software: you can redistribute it and/or modify
14
 * it under the terms of the GNU Affero General Public License, version 3,
15
 * as published by the Free Software Foundation.
16
 *
17
 * This program is distributed in the hope that it will be useful,
18
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20
 * GNU Affero General Public License for more details.
21
 *
22
 * You should have received a copy of the GNU Affero General Public License, version 3,
23
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
24
 *
25
 */
26
27
namespace OC\Mail;
28
29
use Egulias\EmailValidator\EmailValidator;
30
use Egulias\EmailValidator\Validation\RFCValidation;
31
use OCP\Defaults;
32
use OCP\IConfig;
33
use OCP\IL10N;
34
use OCP\IURLGenerator;
35
use OCP\Mail\IAttachment;
36
use OCP\Mail\IEMailTemplate;
37
use OCP\Mail\IMailer;
38
use OCP\ILogger;
39
use OCP\Mail\IMessage;
40
41
/**
42
 * Class Mailer provides some basic functions to create a mail message that can be used in combination with
43
 * \OC\Mail\Message.
44
 *
45
 * Example usage:
46
 *
47
 * 	$mailer = \OC::$server->getMailer();
48
 * 	$message = $mailer->createMessage();
49
 * 	$message->setSubject('Your Subject');
50
 * 	$message->setFrom(array('[email protected]' => 'ownCloud Notifier');
51
 * 	$message->setTo(array('[email protected]' => 'Recipient');
52
 * 	$message->setBody('The message text');
53
 * 	$mailer->send($message);
54
 *
55
 * This message can then be passed to send() of \OC\Mail\Mailer
56
 *
57
 * @package OC\Mail
58
 */
59
class Mailer implements IMailer {
60
	/** @var \Swift_Mailer Cached mailer */
61
	private $instance = null;
62
	/** @var IConfig */
63
	private $config;
64
	/** @var ILogger */
65
	private $logger;
66
	/** @var Defaults */
67
	private $defaults;
68
	/** @var IURLGenerator */
69
	private $urlGenerator;
70
	/** @var IL10N */
71
	private $l10n;
72
73
	/**
74
	 * @param IConfig $config
75
	 * @param ILogger $logger
76
	 * @param Defaults $defaults
77
	 * @param IURLGenerator $urlGenerator
78
	 * @param IL10N $l10n
79
	 */
80
	public function __construct(IConfig $config,
81
						 ILogger $logger,
82
						 Defaults $defaults,
83
						 IURLGenerator $urlGenerator,
84
						 IL10N $l10n) {
85
		$this->config = $config;
86
		$this->logger = $logger;
87
		$this->defaults = $defaults;
88
		$this->urlGenerator = $urlGenerator;
89
		$this->l10n = $l10n;
90
	}
91
92
	/**
93
	 * Creates a new message object that can be passed to send()
94
	 *
95
	 * @return IMessage
96
	 */
97
	public function createMessage(): IMessage {
98
		$plainTextOnly = $this->config->getSystemValue('mail_send_plaintext_only', false);
99
		return new Message(new \Swift_Message(), $plainTextOnly);
100
	}
101
102
	/**
103
	 * @param string|null $data
104
	 * @param string|null $filename
105
	 * @param string|null $contentType
106
	 * @return IAttachment
107
	 * @since 13.0.0
108
	 */
109
	public function createAttachment($data = null, $filename = null, $contentType = null): IAttachment {
110
		return new Attachment(new \Swift_Attachment($data, $filename, $contentType));
111
	}
112
113
	/**
114
	 * @param string $path
115
	 * @param string|null $contentType
116
	 * @return IAttachment
117
	 * @since 13.0.0
118
	 */
119
	public function createAttachmentFromPath(string $path, $contentType = null): IAttachment {
120
		return new Attachment(\Swift_Attachment::fromPath($path, $contentType));
121
	}
122
123
	/**
124
	 * Creates a new email template object
125
	 *
126
	 * @param string $emailId
127
	 * @param array $data
128
	 * @return IEMailTemplate
129
	 * @since 12.0.0
130
	 */
131
	public function createEMailTemplate(string $emailId, array $data = []): IEMailTemplate {
132
		$class = $this->config->getSystemValue('mail_template_class', '');
133
134
		if ($class !== '' && class_exists($class) && is_a($class, EMailTemplate::class, true)) {
135
			return new $class(
136
				$this->defaults,
137
				$this->urlGenerator,
138
				$this->l10n,
139
				$emailId,
140
				$data
141
			);
142
		}
143
144
		return new EMailTemplate(
145
			$this->defaults,
146
			$this->urlGenerator,
147
			$this->l10n,
148
			$emailId,
149
			$data
150
		);
151
	}
152
153
	/**
154
	 * Send the specified message. Also sets the from address to the value defined in config.php
155
	 * if no-one has been passed.
156
	 *
157
	 * @param IMessage|Message $message Message to send
158
	 * @return string[] Array with failed recipients. Be aware that this depends on the used mail backend and
159
	 * therefore should be considered
160
	 * @throws \Exception In case it was not possible to send the message. (for example if an invalid mail address
161
	 * has been supplied.)
162
	 */
163
	public function send(IMessage $message): array {
164
		$debugMode = $this->config->getSystemValue('mail_smtpdebug', false);
165
166
		if (empty($message->getFrom())) {
167
			$message->setFrom([\OCP\Util::getDefaultEmailAddress($this->defaults->getName()) => $this->defaults->getName()]);
168
		}
169
170
		$failedRecipients = [];
171
172
		$mailer = $this->getInstance();
173
174
		// Enable logger if debug mode is enabled
175
		if($debugMode) {
176
			$mailLogger = new \Swift_Plugins_Loggers_ArrayLogger();
177
			$mailer->registerPlugin(new \Swift_Plugins_LoggerPlugin($mailLogger));
178
		}
179
180
		$mailer->send($message->getSwiftMessage(), $failedRecipients);
181
182
		// Debugging logging
183
		$logMessage = sprintf('Sent mail to "%s" with subject "%s"', print_r($message->getTo(), true), $message->getSubject());
184
		$this->logger->debug($logMessage, ['app' => 'core']);
185
		if($debugMode && isset($mailLogger)) {
186
			$this->logger->debug($mailLogger->dump(), ['app' => 'core']);
187
		}
188
189
		return $failedRecipients;
190
	}
191
192
	/**
193
	 * Checks if an e-mail address is valid
194
	 *
195
	 * @param string $email Email address to be validated
196
	 * @return bool True if the mail address is valid, false otherwise
197
	 */
198
	public function validateMailAddress(string $email): bool {
199
		$validator = new EmailValidator();
200
		$validation = new RFCValidation();
201
202
		return $validator->isValid($this->convertEmail($email), $validation);
203
	}
204
205
	/**
206
	 * SwiftMailer does currently not work with IDN domains, this function therefore converts the domains
207
	 *
208
	 * FIXME: Remove this once SwiftMailer supports IDN
209
	 *
210
	 * @param string $email
211
	 * @return string Converted mail address if `idn_to_ascii` exists
212
	 */
213
	protected function convertEmail(string $email): string {
214
		if (!function_exists('idn_to_ascii') || !defined('INTL_IDNA_VARIANT_UTS46') || strpos($email, '@') === false) {
215
			return $email;
216
		}
217
218
		list($name, $domain) = explode('@', $email, 2);
219
		$domain = idn_to_ascii($domain, 0,INTL_IDNA_VARIANT_UTS46);
220
		return $name.'@'.$domain;
221
	}
222
223
	protected function getInstance(): \Swift_Mailer {
224
		if (!is_null($this->instance)) {
225
			return $this->instance;
226
		}
227
228
		$transport = null;
0 ignored issues
show
Unused Code introduced by
$transport is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
229
230
		switch ($this->config->getSystemValue('mail_smtpmode', 'smtp')) {
231
			case 'sendmail':
232
				$transport = $this->getSendMailInstance();
233
				break;
234
			case 'smtp':
235
			default:
236
				$transport = $this->getSmtpInstance();
237
				break;
238
		}
239
240
		return new \Swift_Mailer($transport);
241
	}
242
243
	/**
244
	 * Returns the SMTP transport
245
	 *
246
	 * @return \Swift_SmtpTransport
247
	 */
248
	protected function getSmtpInstance(): \Swift_SmtpTransport {
249
		$transport = new \Swift_SmtpTransport();
250
		$transport->setTimeout($this->config->getSystemValue('mail_smtptimeout', 10));
251
		$transport->setHost($this->config->getSystemValue('mail_smtphost', '127.0.0.1'));
252
		$transport->setPort($this->config->getSystemValue('mail_smtpport', 25));
253
		if ($this->config->getSystemValue('mail_smtpauth', false)) {
254
			$transport->setUsername($this->config->getSystemValue('mail_smtpname', ''));
255
			$transport->setPassword($this->config->getSystemValue('mail_smtppassword', ''));
256
			$transport->setAuthMode($this->config->getSystemValue('mail_smtpauthtype', 'LOGIN'));
257
		}
258
		$smtpSecurity = $this->config->getSystemValue('mail_smtpsecure', '');
259
		if (!empty($smtpSecurity)) {
260
			$transport->setEncryption($smtpSecurity);
261
		}
262
263
		return $transport;
264
	}
265
266
	/**
267
	 * Returns the sendmail transport
268
	 *
269
	 * @return \Swift_SendmailTransport
270
	 */
271
	protected function getSendMailInstance(): \Swift_SendmailTransport {
272
		switch ($this->config->getSystemValue('mail_smtpmode', 'smtp')) {
273
			case 'qmail':
274
				$binaryPath = '/var/qmail/bin/sendmail';
275
				break;
276
			default:
277
				$binaryPath = '/usr/sbin/sendmail';
278
				break;
279
		}
280
281
		return new \Swift_SendmailTransport($binaryPath . ' -bs');
282
	}
283
}
284