MailTemplateService.php 24.4 KB
Newer Older
1
2
3
4
<?php

namespace SGalinski\SgMail\Service;

5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/***************************************************************
 *  Copyright notice
 *
 *  (c) sgalinski Internet Services (https://www.sgalinski.de)
 *
 *  All rights reserved
 *
 *  This script is part of the TYPO3 project. The TYPO3 project is
 *  free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  The GNU General Public License can be found at
 *  http://www.gnu.org/copyleft/gpl.html.
 *
 *  This script is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  This copyright notice MUST APPEAR in all copies of the script!
 ***************************************************************/
28

29
use DateTime;
30
31
32
use SGalinski\SgMail\Domain\Model\Mail;
use SGalinski\SgMail\Domain\Model\Template;
use SGalinski\SgMail\Domain\Repository\MailRepository;
33
use SGalinski\SgMail\Domain\Repository\TemplateRepository;
34
35
use Swift_Attachment;
use Swift_OutputByteStream;
36
37
use TYPO3\CMS\Core\Cache\CacheManager;
use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface;
38
use TYPO3\CMS\Core\Mail\MailMessage;
39
use TYPO3\CMS\Core\Resource\FileInterface;
40
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
41
use TYPO3\CMS\Core\Utility\GeneralUtility;
42
use TYPO3\CMS\Extbase\Domain\Model\FileReference;
43
use TYPO3\CMS\Extbase\Object\ObjectManager;
44
use TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager;
45
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
46
use TYPO3\CMS\Fluid\View\StandaloneView;
47
use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
48

49
50
51
/**
 * MailTemplateService
 */
52
class MailTemplateService {
53
	const MARKER_TYPE_STRING = 'String';
54
55
	const MARKER_TYPE_ARRAY = 'Array';
	const MARKER_TYPE_OBJECT = 'Object';
56
	const MARKER_TYPE_FILE = 'File';
57
	const DEFAULT_LANGUAGE = 'default';
58
	const DEFAULT_TEMPLATE_PATH = 'Resources/Private/Templates/SgMail/';
59
60
	const CACHE_NAME = 'sg_mail_registerArrayCache';
	const CACHE_LIFETIME_IN_SECONDS = 86400;
61

62
	/**
63
	 * @var array $toAddresses
64
	 */
65
	private $toAddresses = [];
66
67

	/**
68
	 * @var string $fromAddress
69
	 */
70
	private $fromAddress;
71
72

	/**
73
	 * @var array $ccAddresses
74
	 */
Paul Ilea's avatar
Paul Ilea committed
75
	private $ccAddresses;
76
77

	/**
78
	 * @var string $replyToAddress
79
	 */
80
	private $replyToAddress;
81
82

	/**
83
	 * @var string $language
84
	 */
85
	private $language = 'default';
86
87

	/**
88
	 * @var boolean $ignoreMailQueue
89
	 */
90
	private $ignoreMailQueue = FALSE;
91
92
93
94
95
96
97

	/**
	 * @var \TYPO3\CMS\Core\Mail\MailMessage $mailMessage
	 */
	private $mailMessage;

	/**
98
	 * @var string $templateName
99
100
101
	 */
	private $templateName;

102
103
104
105
106
	/**
	 * @var string $subject
	 */
	private $subject;

107
	/**
108
	 * @var string $extensionKey
109
110
111
112
	 */
	private $extensionKey;

	/**
113
	 * @var array $markers
114
	 */
Torsten Oppermann's avatar
Torsten Oppermann committed
115
	private $markers;
116

117
118
119
	/**
	 * @var array $bccAddresses
	 */
Paul Ilea's avatar
Paul Ilea committed
120
	private $bccAddresses;
121

122
123
124
125
126
	/**
	 * @var int
	 */
	private $priority = Mail::PRIORITY_LOWEST;

127
128
129
130
131
	/**
	 * @var int
	 */
	private $pid;

132
133
134
135
136
	/**
	 * @var string
	 */
	private $fromName = '';

137
138
139
	/**
	 * @var \SGalinski\SgMail\Domain\Repository\TemplateRepository
	 */
140
141
142
143
144
145
	protected $templateRepository;

	/**
	 * @var \TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager
	 */
	protected $persistenceManager;
146

147
148
149
150
151
	/**
	 * @var \TYPO3\CMS\Extbase\Object\ObjectManager
	 */
	protected $objectManager;

152
153
	/**
	 * MailTemplateService constructor.
Paul Ilea's avatar
Paul Ilea committed
154
	 *
155
156
157
	 * @param string $templateName
	 * @param string $extensionKey
	 * @param string $markers
Paul Ilea's avatar
Paul Ilea committed
158
	 * @throws \InvalidArgumentException
159
	 */
160
161
162
163
164
	public function __construct($templateName = '', $extensionKey = '', $markers = '') {
		$this->templateName = $templateName;
		$this->extensionKey = $extensionKey;
		$this->markers = $markers;

165
166
167
168
169
170
		/** @var ObjectManager objectManager */
		$this->objectManager = GeneralUtility::makeInstance(ObjectManager::class);
		/** @var MailMessage mailMessage */
		$this->mailMessage = $this->objectManager->get(MailMessage::class);
		/** @var TypoScriptSettingsService $typoScriptSettingsService */
		$typoScriptSettingsService = $this->objectManager->get(TypoScriptSettingsService::class);
Torsten Oppermann's avatar
Torsten Oppermann committed
171
		$tsSettings = $typoScriptSettingsService->getSettings(0, 'tx_sgmail');
172
173
174
175
		/** @var TemplateRepository templateRepository */
		$this->templateRepository = $this->objectManager->get(TemplateRepository::class);
		/** @var PersistenceManager persistenceManager */
		$this->persistenceManager = $this->objectManager->get(PersistenceManager::class);
176

177
		// use defaultMailFromAddress if it is provided in LocalConfiguration.php; use the sg_mail TS setting as fallback
178
		if (!filter_var($GLOBALS['TYPO3_CONF_VARS']['MAIL']['defaultMailFromAddress'], FILTER_VALIDATE_EMAIL)) {
179
180
			$this->fromAddress = $GLOBALS['TYPO3_CONF_VARS']['MAIL']['defaultMailFromAddress'];
		} else {
Torsten Oppermann's avatar
Torsten Oppermann committed
181
			$this->fromAddress = $tsSettings['mail']['default']['from'];
182

Torsten Oppermann's avatar
Torsten Oppermann committed
183
			if (!filter_var($tsSettings['mail']['default']['from'], FILTER_VALIDATE_EMAIL)) {
184
185
				$this->fromAddress = 'noreply@example.org';
			} else {
Torsten Oppermann's avatar
Torsten Oppermann committed
186
				$this->fromAddress = $tsSettings['mail']['default']['from'];
187
			}
188
189
		}

190
		$this->mailMessage->setFrom($this->fromAddress);
191

Torsten Oppermann's avatar
Torsten Oppermann committed
192
193
		$this->bccAddresses = GeneralUtility::trimExplode(',', $tsSettings['mail']['default']['bcc']);
		$this->ccAddresses = GeneralUtility::trimExplode(',', $tsSettings['mail']['default']['cc']);
194
195
196
197
198
199
200
201
202
203
204
205
206

		foreach ($this->bccAddresses as $index => $email) {
			if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
				unset($this->bccAddresses[$index]);
			}
		}

		foreach ($this->ccAddresses as $index => $email) {
			if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
				unset($this->ccAddresses[$index]);
			}
		}

207
		if (count($this->bccAddresses) > 0) {
208
209
210
			$this->mailMessage->setBcc($this->bccAddresses);
		}

211
		if (count($this->ccAddresses) > 0) {
212
213
			$this->mailMessage->setCc($this->ccAddresses);
		}
214
215
	}

216
217
218
219
220
221
222
223
224
	/**
	 * Return default markers for sg_mail
	 *
	 * @param string $translationKey
	 * @param array $marker
	 * @param string $extensionKey
	 * @return array
	 */
	public static function getDefaultTemplateMarker($translationKey, array $marker, $extensionKey = 'sg_mail') {
225
		$languagePath = 'LLL:EXT:' . $extensionKey . '/Resources/Private/Language/locallang.xlf:' . $translationKey;
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245

		// Need the key for translations
		if (trim($extensionKey) === '') {
			return [];
		}

		$generatedMarker = [];
		foreach ($marker as $markerName) {
			$generatedMarker[] = [
				'marker' => $markerName,
				'value' => $languagePath . '.example.' . $markerName,
				'description' => $languagePath . '.description.' . $markerName,
				'backend_translation_key' => $translationKey . '.example.' . $markerName,
				'extension_key' => $extensionKey
			];
		}

		return $generatedMarker;
	}

246
	/**
247
	 * Send the Email
248
	 *
Torsten Oppermann's avatar
Torsten Oppermann committed
249
	 * @param boolean $isPreview
250
	 * @return boolean email was sent or added to mail queue successfully?
251
252
253
	 * @throws \TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException
	 * @throws \InvalidArgumentException
	 * @throws \BadFunctionCallException
254
	 * @throws \TYPO3\CMS\Extbase\Persistence\Exception\IllegalObjectTypeException
255
	 */
256
	public function sendEmail($isPreview = FALSE): bool {
257
258
259
260
261
262
263
264
		if (TYPO3_MODE === 'FE') {
			/** @var TypoScriptFrontendController $tsfe */
			$tsfe = $GLOBALS['TSFE'];
			$pageUid = $tsfe->id;
		} else {
			$pageUid = (int) GeneralUtility::_GP('id');
		}

265
266
267
		if ($this->pid) {
			$pageUid = $this->pid;
		}
268
		$siteRootId = BackendService::getSiteRoot($pageUid);
269

270
		/** @var Template $template */
271
		$template = $this->templateRepository->findOneByTemplate(
272
			$this->extensionKey, $this->templateName, $this->language, $siteRootId
273
		);
274

275
276
277
278
279
280
		if ($template === NULL) {
			$template = $this->templateRepository->findOneByTemplate(
				$this->extensionKey, $this->templateName, 'default', $siteRootId
			);
		}

281
282
283
284
285
		// if there is a template, prefer those values
		if ($template) {
			$this->loadTemplateValues($template);
		}

Torsten Oppermann's avatar
Torsten Oppermann committed
286
		$defaultTemplateContent = NULL;
287
288
		// If there is no template for this language, use the default template
		if ($template === NULL) {
289

290
			$templatePath = self::getRegisterArray()[$this->extensionKey][$this->templateName]['templatePath'];
291

292
293
294
295
296
297
			// only standard template file is considered since version 4.1
			$defaultTemplateFile = $templatePath . 'template.html';
			if (file_exists($defaultTemplateFile)) {
				$defaultTemplateContent = file_get_contents($defaultTemplateFile);
			} else {
				return FALSE;
298
			}
299
		} elseif (filter_var($template->getToAddress(), FILTER_VALIDATE_EMAIL)) {
300
			$this->setToAddresses(trim($template->getToAddress()));
301
302
		}

Torsten Oppermann's avatar
Torsten Oppermann committed
303
304
		if ($isPreview) {
			$previewMarker = [];
Paul Ilea's avatar
Paul Ilea committed
305
			/** @var array $markerArray */
306
			$markerArray = self::getRegisterArray()[$this->extensionKey][$this->templateName]['marker'];
Torsten Oppermann's avatar
Torsten Oppermann committed
307
			foreach ($markerArray as $marker) {
308
309
310
311
312
313
314
315
316
317
318
319
				$markerPath = GeneralUtility::trimExplode('.', $marker['marker']);
				$temporaryMarkerArray = [];
				foreach (array_reverse($markerPath) as $index => $markerPathSegment) {
					if ($index === 0) {
						if ($marker['backend_translation_key']) {
							$temporaryMarkerArray[$markerPathSegment] = LocalizationUtility::translate(
								$marker['backend_translation_key'], $marker['extension_key']
							);
						} else {
							$temporaryMarkerArray[$markerPathSegment] = $marker['value'];
						}
					} else {
320
						$temporaryMarkerArray = [$markerPathSegment => $temporaryMarkerArray];
321
					}
322
				}
323
				$previewMarker = array_merge_recursive($previewMarker, $temporaryMarkerArray);
Torsten Oppermann's avatar
Torsten Oppermann committed
324
			}
325
			$this->setIgnoreMailQueue(TRUE);
Torsten Oppermann's avatar
Torsten Oppermann committed
326
327
328
			$this->setMarkers($previewMarker);
		}

329
		/** @var StandaloneView $emailView */
330
		$emailView = $this->objectManager->get(StandaloneView::class);
331
		$emailView->assignMultiple($this->markers);
332
		if (NULL === $defaultTemplateContent) {
333
334
335
			$emailView->setTemplateSource(\trim($template->getSubject()));
			$subject = $emailView->render();

336
337
			$emailView->setTemplateSource($template->getContent());
		} else {
338
			$subject = self::getRegisterArray()[$this->extensionKey][$this->templateName]['subject'];
339
340
			if (\is_array($subject)) {
				$subject = \trim(
341
342
					self::getRegisterArray()[$this->extensionKey][$this->templateName]['subject'][$this->language]
				);
343
			}
344
345
346
347
348
349
350
			if ($subject === NULL && $this->subject !== NULL) {
				$subject = $this->subject;
			}
			if ($subject !== NULL) {
				$emailView->setTemplateSource($subject);
				$subject = $emailView->render();
			}
351
			$emailView->setTemplateSource($defaultTemplateContent);
352
		}
353

Paul Ilea's avatar
Paul Ilea committed
354
		if ($this->subject !== '' && $this->subject !== NULL) {
355
356
357
			$subject = $this->subject;
		}

358
		$this->mailMessage->setSubject($subject);
359

360
		$emailBody = $emailView->render();
361

362
363
364
		// insert <br /> tags, but replace every instance of three or more successive breaks with just two.
		$emailBody = nl2br($emailBody);
		$emailBody = preg_replace('/(<br[\s]?[\/]?>[\s]*){3,}/', '<br /><br />', $emailBody);
365

366
367
368
		$isTemplateBlacklisted = self::isTemplateBlacklisted(
			$this->extensionKey, $this->templateName, $siteRootId
		);
369
		if ($this->ignoreMailQueue && !$isTemplateBlacklisted) {
370
			$this->mailMessage->setBody($emailBody, 'text/html');
371
372
373
            $plaintextService = GeneralUtility::makeInstance(PlaintextService::class);
            $plainTextBody = $plaintextService->makePlain($emailBody);
            $this->mailMessage->addPart($plainTextBody, 'text/plain');
374
			$this->mailMessage->send();
375
			$dateTime = new DateTime();
376
			$currentTimestamp = $dateTime->getTimestamp();
377
378
379
380

			if (!$isPreview) {
				$this->addMailToMailQueue(
					$this->extensionKey, $this->templateName, $subject, $emailBody, $this->priority,
381
					$currentTimestamp, $currentTimestamp, $this->language, $siteRootId
382
383
				);
			}
384

385
		} else {
386
387
			if (!$isPreview) {
				$this->addMailToMailQueue(
388
					$this->extensionKey, $this->templateName, $subject, $emailBody, $this->priority, 0, 0,
389
390
391
					$this->language, $siteRootId
				);
			}
392
		}
393
394

		return TRUE;
395
396
397
	}

	/**
398
	 * Adds a new mail to the mail queue.
399
	 *
400
401
	 * @param string $extensionKey
	 * @param string $templateName
402
	 * @param string $subject
403
	 * @param string $emailBody
404
	 * @param int $sendingTime
405
	 * @param int $priority
406
	 * @param int $lastSendingTime
407
	 * @param string $language
408
	 * @param int $pid
409
410
	 * @throws \InvalidArgumentException
	 * @throws \BadFunctionCallException
Paul Ilea's avatar
Paul Ilea committed
411
	 * @throws \TYPO3\CMS\Extbase\Persistence\Exception\IllegalObjectTypeException
412
	 * @throws \TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException
413
	 */
414
	private function addMailToMailQueue(
415
		$extensionKey, $templateName, $subject, $emailBody, $priority, $sendingTime = 0,
416
		$lastSendingTime = 0, $language = self::DEFAULT_LANGUAGE, $pid = 0
417
	) {
418
		$mail = $this->objectManager->get(Mail::class);
419
		$mail->setPid($pid);
420
421
		$mail->setExtensionKey($extensionKey);
		$mail->setTemplateName($templateName);
422
		$mail->setLanguage($language);
423
		$mail->setBlacklisted(self::isTemplateBlacklisted($extensionKey, $templateName, $pid));
424

425
		$mail->setFromAddress($this->fromAddress);
426
		$mail->setFromName($this->fromName);
427

428
		$mail->setToAddress($this->toAddresses);
429
		$mail->setMailSubject($subject);
430
		$mail->setMailBody($emailBody);
431
		$mail->setPriority($priority);
432
433
		$mail->setBccAddresses($this->bccAddresses);
		$mail->setCcAddresses($this->ccAddresses);
434
		$mail->setSendingTime($sendingTime);
435
		$mail->setLastSendingTime($lastSendingTime);
436
		$mail->setReplyTo($this->replyToAddress);
437
438
439
440
441
		foreach ($this->markers as $marker) {
			if ($marker instanceof FileReference) {
				$mail->addAttachment($marker);
			}
		}
442

443
		$mailRepository = $this->objectManager->get(MailRepository::class);
444
		$mailRepository->add($mail);
445
		$this->persistenceManager->persistAll();
446
	}
447

448
449
450
451
	/**
	 * Send a Mail from the queue, identified by its id
	 *
	 * @param int $uid
Paul Ilea's avatar
Paul Ilea committed
452
453
	 * @throws \TYPO3\CMS\Extbase\Persistence\Exception\IllegalObjectTypeException
	 * @throws \TYPO3\CMS\Extbase\Persistence\Exception\UnknownObjectException
454
455
456
457
	 */
	public function sendMailFromQueue($uid) {
		$mailRepository = $this->objectManager->get(MailRepository::class);
		/** @var Mail $mailToSend */
458
		$mailToSend = $mailRepository->findOneByUid($uid);
459

460
		if ($mailToSend && !$mailToSend->getBlacklisted()) {
461
			$this->mailMessage->setBody($mailToSend->getMailBody(), 'text/html');
462
463
464
			$plaintextService = GeneralUtility::makeInstance(PlaintextService::class);
			$plaintextBody = $plaintextService->makePlain($mailToSend->getMailBody());
			$this->mailMessage->addPart($plaintextBody, 'text/plain');
465
			$this->mailMessage->setTo(trim($mailToSend->getToAddress()));
466
467
			$this->mailMessage->setFrom($mailToSend->getFromAddress(), $mailToSend->getFromName());
			$this->mailMessage->setSubject($mailToSend->getMailSubject());
468

469
			if ($mailToSend->getBccAddresses()) {
470
471
472
				$this->mailMessage->setBcc(GeneralUtility::trimExplode(',', $mailToSend->getBccAddresses()));
			}

473
			if ($mailToSend->getCcAddresses()) {
474
475
476
477
478
479
				$this->mailMessage->setCc(GeneralUtility::trimExplode(',', $mailToSend->getCcAddresses()));
			}

			if ($mailToSend->getReplyTo()) {
				$this->mailMessage->setReplyTo($mailToSend->getReplyTo());
			}
480
481
482
483
484
485
486
487
488
489
490
491
			$attachments = $mailToSend->getAttachments();
			if ($attachments->count() > 0) {
				foreach ($attachments as $attachment) {
					/**
					 * @var FileReference $attachment
					 */
					$file = $attachment->getOriginalResource()->getOriginalFile();
					$this->mailMessage->attach(
						\Swift_Attachment::newInstance($file->getContents(), $file->getName(), $file->getMimeType())
					);
				}
			}
492
			$dateTime = new DateTime();
493
494
495
			if ((int)$mailToSend->getSendingTime() === 0) {
			    $mailToSend->setSendingTime($dateTime->getTimestamp());
            }
496
			$mailToSend->setLastSendingTime($dateTime->getTimestamp());
497
			$this->mailMessage->send();
498
			$mailRepository->update($mailToSend);
499
500
501
		}
	}

502
	/**
503
	 * @param string $toAddresses
504
505
	 * @return MailTemplateService
	 */
506
	public function setToAddresses($toAddresses) {
507
		$toAddresses = preg_replace('~\x{00a0}~siu', ' ', $toAddresses);
508
509
		$this->toAddresses = trim($toAddresses);
		$this->mailMessage->setTo(trim($toAddresses));
510
511
512
513
		return $this;
	}

	/**
514
	 * @param string $fromAddress
515
	 * @param string $fromName
516
517
	 * @return MailTemplateService
	 */
518
	public function setFromAddress($fromAddress, $fromName = '') {
519
520
521
522
523
		if ($fromAddress) {
			$this->fromAddress = $fromAddress;
			$this->mailMessage->setFrom($fromAddress, $fromName);
		}

524
525
526
527
		return $this;
	}

	/**
528
	 * @param string $ccAddresses
529
530
	 * @return MailTemplateService
	 */
531
	public function setCcAddresses($ccAddresses) {
532
533
		if ($ccAddresses) {
			$this->ccAddresses = $ccAddresses;
534
			$this->mailMessage->setCc(GeneralUtility::trimExplode(',', $this->ccAddresses));
535
536
		}

537
538
539
540
		return $this;
	}

	/**
541
	 * @param string $replyToAddress
542
543
	 * @return MailTemplateService
	 */
544
	public function setReplyToAddress($replyToAddress) {
545
546
547
548
549
		if ($replyToAddress) {
			$this->replyToAddress = $replyToAddress;
			$this->mailMessage->setReplyTo($replyToAddress);
		}

550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
		return $this;
	}

	/**
	 * @param string $language
	 * @return MailTemplateService
	 */
	public function setLanguage($language) {
		$this->language = $language;
		return $this;
	}

	/**
	 * @param boolean $ignoreMailQueue
	 * @return MailTemplateService
	 */
	public function setIgnoreMailQueue($ignoreMailQueue) {
		$this->ignoreMailQueue = $ignoreMailQueue;
		return $this;
	}

	/**
	 * @param string $templateName
	 * @return MailTemplateService
	 */
	public function setTemplateName($templateName) {
		$this->templateName = $templateName;
		return $this;
	}

	/**
	 * @param string $extensionKey
	 * @return MailTemplateService
	 */
	public function setExtensionKey($extensionKey) {
		$this->extensionKey = $extensionKey;
		return $this;
	}

589
	/**
590
	 * @param array $markers
591
592
	 * @return MailTemplateService
	 */
593
594
	public function setMarkers(array $markers) {
		$this->markers = $markers;
595
596
		return $this;
	}
597
598

	/**
599
	 * @param string $bccAddresses
600
601
	 * @return MailTemplateService
	 */
602
	public function setBccAddresses($bccAddresses) {
603
604
		if ($bccAddresses) {
			$this->bccAddresses = $bccAddresses;
605
			$this->mailMessage->setBcc(GeneralUtility::trimExplode(',', $this->bccAddresses));
606
607
		}

608
609
610
		return $this;
	}

611
612
613
614
615
616
617
618
	/**
	 * @param int $priority
	 * @return MailTemplateService
	 */
	public function setPriority($priority) {
		$this->priority = $priority;
		return $this;
	}
619
620
621

	/**
	 * @param Swift_OutputByteStream $data
Paul Ilea's avatar
Paul Ilea committed
622
	 * @param string $filename
623
624
625
626
627
628
629
630
631
632
633
	 * @param string $contentType
	 * @return MailTemplateService
	 */
	public function addAttachment($data, $filename, $contentType) {
		$attachment = Swift_Attachment::newInstance()
			->setFilename($filename)
			->setContentType($contentType)
			->setBody($data);
		$this->mailMessage->attach($attachment);
		return $this;
	}
634

635
636
637
	/**
	 * Add a file resource as attachment
	 *
638
	 * @param FileInterface|FileReference $file
639
640
	 * @return MailTemplateService
	 */
641
642
643
644
645
646
647
648
649
650
651
	public function addFileResourceAttachment($file) {
		if ($file instanceof FileReference) {
			$this->markers[] = $file;
			$file = $file->getOriginalResource()->getOriginalFile();
		} elseif ($file instanceof FileInterface) {
			$fileReference = $this->objectManager->get(FileReference::class);
			$fileReference->setOriginalResource($file);
			$this->markers[] = $fileReference;
		}
		$this->addAttachment($file->getContents(), $file->getName(), $file->getMimeType());
		return $this;
652
653
	}

654
655
656
657
658
659
660
	/**
	 * @return MailMessage
	 */
	public function getMailMessage() {
		return $this->mailMessage;
	}

661
662
663
664
665
666
	/**
	 * use all values from the given template
	 *
	 * @param Template $template
	 */
	private function loadTemplateValues($template) {
667
668
669
670
671
672
673
674
675
676
677
678
679
680
		$fromName = $template->getFromName();
		if ($fromName === '' && $GLOBALS['TYPO3_CONF_VARS']['MAIL']['defaultMailFromName']) {
			$fromName = $GLOBALS['TYPO3_CONF_VARS']['MAIL']['defaultMailFromName'];
		}

		$fromMail = $template->getFromMail();
		if (!filter_var($fromMail, FILTER_VALIDATE_EMAIL)) {
			$fromMail = $GLOBALS['TYPO3_CONF_VARS']['MAIL']['defaultMailFromAddress'];
			if (!filter_var($GLOBALS['TYPO3_CONF_VARS']['MAIL']['defaultMailFromAddress'], FILTER_VALIDATE_EMAIL)) {
				$fromMail = 'noreply@example.com';
			}
		}

		$this->setFromAddress($fromMail, $fromName);
681
682
683
		$this->setCcAddresses($template->getCc());
		$this->setBccAddresses($template->getBcc());
		$this->setReplyToAddress($template->getReplyTo());
684
		$this->setFromName($fromName);
685
686
687
688
689
690
691
692
		$this->setReplyToAddress($template->getReplyTo());
	}

	/**
	 * @param string $fromName
	 */
	public function setFromName($fromName) {
		$this->fromName = $fromName;
693
	}
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710

	/**
	 * Provides translation for the marker data type
	 *
	 * @param string $markerType
	 */
	public static function getReadableMarkerType($markerType) {
		switch ($markerType) {
			case self::MARKER_TYPE_STRING :
				LocalizationUtility::translate('backend.marker.type.string', 'sg_mail');
				break;
			case self::MARKER_TYPE_ARRAY :
				LocalizationUtility::translate('backend.marker.type.array', 'sg_mail');
				break;
			case self::MARKER_TYPE_OBJECT :
				LocalizationUtility::translate('backend.marker.type.object', 'sg_mail');
				break;
711
712
713
			case self::MARKER_TYPE_FILE:
				LocalizationUtility::translate('backend.marker.type.file', 'sg_mail');
				break;
714
715
716
717
			default:
				LocalizationUtility::translate('backend.marker.type.mixed', 'sg_mail');
		}
	}
718
719
720
721
722
723
724
725
726
727
728

	/**
	 * set the page id from which this was called
	 *
	 * @param int $pid
	 * @return MailTemplateService
	 */
	public function setPid($pid) {
		$this->pid = (int) $pid;
		return $this;
	}
729

730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
	/**
	 * Get all registered templates
	 *
	 * @return array
	 * @throws \TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException
	 * @throws \BadFunctionCallException
	 * @throws \InvalidArgumentException
	 */
	public static function getRegisterArray() {
		/** @var CacheManager $cacheManager */
		$cacheManager = GeneralUtility::makeInstance(CacheManager::class);
		/** @var FrontendInterface $cache */
		$cache = $cacheManager->getCache(self::CACHE_NAME);
		$cacheId = md5('sg_mail');
		/** @var array entry */
		if (($entry = $cache->get($cacheId)) === FALSE) {
			$entry = self::registerExtensions();

			if ($entry === NULL) {
				$entry = [];
			}

			$cache->set($cacheId, $entry, [], self::CACHE_LIFETIME_IN_SECONDS);
		}

		return $entry;
	}

758
759
760
761
762
	/**
	 * Iterate over all installed extensions and look for sg_mail configuration files
	 * If found, register the template(s)
	 *
	 * @throws \BadFunctionCallException
763
	 * @return array
764
	 */
765
	public static function registerExtensions(): array {
766
		// clear registerArray
767
		$registerArray = [];
768
769
770
771
772
773
774
775
776
777

		$extensionList = ExtensionManagementUtility::getLoadedExtensionListArray();

		foreach ($extensionList as $extensionName) {
			$extensionConfigDirectory = ExtensionManagementUtility::extPath($extensionName);
			$extensionConfigDirectory .= '/Configuration/MailTemplates';
			$configFiles = GeneralUtility::getFilesInDir($extensionConfigDirectory);

			foreach ($configFiles as $configFile) {
				$configArray = (include $extensionConfigDirectory . '/' . $configFile);
778
779
780
781
782
783
784
785
786
787
788
789
790
				$extensionKey = $configArray['extension_key'];
				$templateKey = $configArray['template_key'];

				// transform template directory name: your_templates => YourTemplates/
				$templateDirectoryParts = GeneralUtility::trimExplode('_', $configArray['template_key']);
				$templateDirectory = '';
				foreach ($templateDirectoryParts as $part) {
					$templateDirectory .= ucfirst($part);
				}
				$templateDirectory .= '/';
				$templatePath = ExtensionManagementUtility::extPath(
						$extensionName
					) . self::DEFAULT_TEMPLATE_PATH . $templateDirectory;
791

792
793
794
				if ($configArray['template_path']) {
					$templatePath = $configArray['template_key'];
				}
795

796
797
798
799
800
801
802
803
804
805
806
807
808
				$description = $configArray['description'];
				$subject = $configArray['subject'];
				$marker = $configArray['markers'];

				$registerArray[$extensionKey][$templateKey] = [
					'templatePath' => $templatePath,
					'description' => $description,
					'marker' => $marker,
					'extension' => $extensionKey,
					'templateName' => $templateKey,
					'subject' => $subject
				];
			}
809
810
		}

811
		return $registerArray;
812
	}
813
814
815
816
817
818
819
820
821
822
823
824
825

	/**
	 * Checks if a template is blacklisted for a given siterootId
	 *
	 * @param string $extensionKey
	 * @param string $templateName
	 * @param int $siteRootId
	 * @return boolean
	 * @throws \InvalidArgumentException
	 * @throws \BadFunctionCallException
	 * @throws \TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException
	 */
	public static function isTemplateBlacklisted($extensionKey, $templateName, $siteRootId): bool {
826
		$nonBlacklistedTemplates = BackendService::getNonBlacklistedTemplates($siteRootId);
827

828
829
		if ($nonBlacklistedTemplates[$extensionKey]) {
			return $nonBlacklistedTemplates[$extensionKey][$templateName] ? FALSE : TRUE;
830
831
832
833
		}

		return TRUE;
	}
834
835
836
837
838
839
840
841
842
843
844
845
846
847

	/**
	 * @return string
	 */
	public function getSubject(): string {
		return $this->subject;
	}

	/**
	 * @param string $subject
	 */
	public function setSubject(string $subject) {
		$this->subject = $subject;
	}
848
}