MailTemplateService.php 25.2 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
use TYPO3\CMS\Core\Database\ConnectionPool;
37
38
use TYPO3\CMS\Core\Mail\MailMessage;
use TYPO3\CMS\Core\Utility\GeneralUtility;
39
use TYPO3\CMS\Extbase\Domain\Model\FileReference;
40
use TYPO3\CMS\Extbase\Object\ObjectManager;
41
use TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager;
42
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
43
use TYPO3\CMS\Fluid\View\StandaloneView;
44
use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
45

46
47
48
/**
 * MailTemplateService
 */
49
class MailTemplateService {
Torsten Oppermann's avatar
Torsten Oppermann committed
50
51
52
53
54
55
56
57
58
59
	public const MARKER_TYPE_STRING = 'String';
	public const MARKER_TYPE_ARRAY = 'Array';
	public const MARKER_TYPE_OBJECT = 'Object';
	public const MARKER_TYPE_FILE = 'File';
	public const DEFAULT_LANGUAGE = 'default';
	public const DEFAULT_TEMPLATE_PATH = 'Resources/Private/Templates/SgMail/';
	public const CACHE_NAME = 'sg_mail_registerArrayCache';
	public const CACHE_LIFETIME_IN_SECONDS = 86400;
	public const REGISTER_FILE = 'Register.php';
	public const CONFIG_PATH = 'Configuration/MailTemplates';
60

61
	/**
62
	 * @var string $toAddresses
63
	 */
64
	private $toAddresses = '';
65
66

	/**
67
	 * @var string $fromAddress
68
	 */
69
	private $fromAddress = '';
70
71

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

	/**
77
	 * @var string $replyToAddress
78
	 */
79
	private $replyToAddress = '';
80
81

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

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

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

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

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

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

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

116
117
118
119
120
	/**
	 * @var array $markerLabels
	 */
	private $markerLabels;

121
	/**
122
	 * @var string $bccAddresses
123
	 */
Paul Ilea's avatar
Paul Ilea committed
124
	private $bccAddresses;
125

126
127
128
129
130
	/**
	 * @var int
	 */
	private $priority = Mail::PRIORITY_LOWEST;

131
132
133
134
135
	/**
	 * @var int
	 */
	private $pid;

136
137
138
139
140
	/**
	 * @var string
	 */
	private $fromName = '';

141
142
143
	/**
	 * @var \SGalinski\SgMail\Domain\Repository\TemplateRepository
	 */
144
145
146
147
148
149
	protected $templateRepository;

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

151
152
153
154
155
	/**
	 * @var \TYPO3\CMS\Extbase\Object\ObjectManager
	 */
	protected $objectManager;

156
157
	/**
	 * MailTemplateService constructor.
Paul Ilea's avatar
Paul Ilea committed
158
	 *
159
160
	 * @param string $templateName
	 * @param string $extensionKey
161
	 * @param array $markers
162
	 * @param array $markerLabels
Paul Ilea's avatar
Paul Ilea committed
163
	 * @throws \InvalidArgumentException
164
	 */
165
	public function __construct($templateName = '', $extensionKey = '', $markers = [], $markerLabels = []) {
166
167
168
		$this->templateName = $templateName;
		$this->extensionKey = $extensionKey;
		$this->markers = $markers;
169
		$this->markerLabels = $markerLabels;
170

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

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

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

192
193
194
195
196
		if ($GLOBALS['TYPO3_CONF_VARS']['MAIL']['defaultMailFromName']) {
			$this->fromName = $GLOBALS['TYPO3_CONF_VARS']['MAIL']['defaultMailFromName'];
		}

		$this->mailMessage->setFrom($this->fromAddress, $this->fromName);
197

Torsten Oppermann's avatar
Torsten Oppermann committed
198
199
		$this->bccAddresses = GeneralUtility::trimExplode(',', $tsSettings['mail']['default']['bcc']);
		$this->ccAddresses = GeneralUtility::trimExplode(',', $tsSettings['mail']['default']['cc']);
200
201
202
203
204
205
206
207
208
209
210
211
212

		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]);
			}
		}

213
		if (\count($this->bccAddresses) > 0) {
214
215
216
			$this->mailMessage->setBcc($this->bccAddresses);
		}

217
		if (\count($this->ccAddresses) > 0) {
218
219
			$this->mailMessage->setCc($this->ccAddresses);
		}
220
221
	}

222
223
224
	/**
	 * @param string $fromName
	 */
Torsten Oppermann's avatar
Torsten Oppermann committed
225
	public function setFromName($fromName): void {
226
227
228
229
230
231
232
233
		$this->fromName = $fromName;
	}

	/**
	 * Provides translation for the marker data type
	 *
	 * @param string $markerType
	 */
Torsten Oppermann's avatar
Torsten Oppermann committed
234
	public static function getReadableMarkerType($markerType): void {
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
		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;
			case self::MARKER_TYPE_FILE:
				LocalizationUtility::translate('backend.marker.type.file', 'sg_mail');
				break;
			default:
				LocalizationUtility::translate('backend.marker.type.mixed', 'sg_mail');
		}
	}

	/**
	 * @param string $toAddresses
	 * @return MailTemplateService
	 */
	public function setToAddresses($toAddresses): MailTemplateService {
		$normalizedToAddresses = trim(preg_replace('~\x{00a0}~iu', ' ', $toAddresses));
		$this->toAddresses = $normalizedToAddresses;

		$addressesArray = GeneralUtility::trimExplode(',', $normalizedToAddresses, TRUE);
		if (\count($addressesArray) > 1) {
			$normalizedToAddresses = $addressesArray;
		}
		$this->mailMessage->setTo($normalizedToAddresses);
		return $this;
	}

	/**
	 * @param string $fromAddress
	 * @param string $fromName
	 * @return MailTemplateService
	 */
	public function setFromAddress($fromAddress, $fromName = ''): MailTemplateService {
		if ($fromAddress) {
			$this->fromAddress = $fromAddress;
			$this->mailMessage->setFrom($fromAddress, $fromName);
		}

		return $this;
	}

	/**
	 * @param string $ccAddresses
	 * @return MailTemplateService
	 */
	public function setCcAddresses($ccAddresses): MailTemplateService {
		if ($ccAddresses) {
			$this->ccAddresses = $ccAddresses;
			$this->mailMessage->setCc(GeneralUtility::trimExplode(',', $this->ccAddresses));
		}

		return $this;
	}

	/**
	 * @param string $replyToAddress
	 * @return MailTemplateService
	 */
	public function setReplyToAddress($replyToAddress): MailTemplateService {
		if ($replyToAddress) {
			$this->replyToAddress = $replyToAddress;
			$this->mailMessage->setReplyTo($replyToAddress);
		}

		return $this;
	}

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

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

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

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

	/**
	 * @param array $markers
	 * @return MailTemplateService
	 */
	public function setMarkers(array $markers): MailTemplateService {
		$this->markers = $markers;
351
		foreach($markers as $key => $currentMarker) {
352
			if (!\is_array($currentMarker) || !isset($currentMarker['markerLabel'])) {
353
354
355
356
357
				continue;
			}
			$this->markerLabels[$key] = $currentMarker['markerLabel'];
		}

358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
		return $this;
	}

	/**
	 * @param string $bccAddresses
	 * @return MailTemplateService
	 */
	public function setBccAddresses($bccAddresses): MailTemplateService {
		if ($bccAddresses) {
			$this->bccAddresses = $bccAddresses;
			$this->mailMessage->setBcc(GeneralUtility::trimExplode(',', $this->bccAddresses));
		}

		return $this;
	}

	/**
	 * @param int $priority
	 * @return MailTemplateService
	 */
	public function setPriority($priority): MailTemplateService {
		$this->priority = $priority;
		return $this;
	}

	/**
	 * @param Swift_OutputByteStream $data
	 * @param string $filename
	 * @param string $contentType
	 * @return MailTemplateService
	 */
	public function addAttachment($data, $filename, $contentType): MailTemplateService {
		$attachment = Swift_Attachment::newInstance()
			->setFilename($filename)
			->setContentType($contentType)
			->setBody($data);
		$this->mailMessage->attach($attachment);
		return $this;
	}

	/**
399
400
401
	 * Adds a file resource as attachment
	 *
	 * @param FileReference $file
402
403
404
	 *
	 * @return MailTemplateService
	 */
405
406
	public function addFileResourceAttachment(FileReference $file): MailTemplateService {
		$this->markers[] = $file;
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
		return $this;
	}

	/**
	 * @return MailMessage
	 */
	public function getMailMessage(): MailMessage {
		return $this->mailMessage;
	}

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

	/**
	 * Checks if a template is blacklisted for a given siteroot id
	 *
	 * @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 {
		$nonBlacklistedTemplates = BackendService::getNonBlacklistedTemplates($siteRootId);
		if ($nonBlacklistedTemplates[$extensionKey]) {
			return $nonBlacklistedTemplates[$extensionKey][$templateName] ? FALSE : TRUE;
		}

		return TRUE;
	}

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

	/**
	 * @param string $subject
	 */
Torsten Oppermann's avatar
Torsten Oppermann committed
458
	public function setSubject(string $subject): void {
459
460
461
		$this->subject = $subject;
	}

462
463
464
465
466
467
468
469
	/**
	 * Return default markers for sg_mail
	 *
	 * @param string $translationKey
	 * @param array $marker
	 * @param string $extensionKey
	 * @return array
	 */
470
	public static function getDefaultTemplateMarker($translationKey, array $marker, $extensionKey = 'sg_mail'): array {
471
		$languagePath = 'LLL:EXT:' . $extensionKey . '/Resources/Private/Language/locallang.xlf:' . $translationKey;
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491

		// 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;
	}

492
	/**
493
	 * Send the Email
494
	 *
495
496
	 * @param bool $isPreview
	 * @return bool email was sent or added to mail queue successfully?
497
498
499
	 * @throws \TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException
	 * @throws \InvalidArgumentException
	 * @throws \BadFunctionCallException
500
	 * @throws \TYPO3\CMS\Extbase\Persistence\Exception\IllegalObjectTypeException
501
	 * @throws \Exception
502
	 */
503
	public function sendEmail($isPreview = FALSE): bool {
504
		$success = FALSE;
505
		if (TYPO3_MODE === 'FE') {
506
507
508
			/** @var TypoScriptFrontendController $typoscriptFrontendController */
			$typoscriptFrontendController = $GLOBALS['TSFE'];
			$pageUid = (int) $typoscriptFrontendController->id;
509
510
511
512
		} else {
			$pageUid = (int) GeneralUtility::_GP('id');
		}

513
		if ($this->pid) {
514
			$pageUid = $this->pid;
515
		}
516

517
		if ($pageUid === 0) {
518
519
			$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable(
				'pages'
520
			);
521
			$rootPageRows = $queryBuilder->select('*')
522
				->from('pages')
523
524
525
526
527
528
529
530
531
532
533
534
				->where(
					$queryBuilder->expr()->eq(
						'is_siteroot', 1
					)
				)
				->andWhere(
					$queryBuilder->expr()->eq(
						'hidden', 0
					)
				)
				->execute()->fetchAll();

535
536
537
			if ($rootPageRows && \count($rootPageRows)) {
				$pageUid = (int) $rootPageRows[0]['uid'];
			}
538
		}
539
		$siteRootId = BackendService::getSiteRoot($pageUid);
540

541
542
		$isTemplateBlacklisted = self::isTemplateBlacklisted($this->extensionKey, $this->templateName, $siteRootId);
		if ($isTemplateBlacklisted) {
543
544
545
			// @TODO: This needs to be changed, because if the template is blacklisted, the email can not be sent
			$success = TRUE;
			return $success;
546
547
		}

548
		/** @var Template $template */
549
		$template = $this->templateRepository->findOneByTemplate(
550
			$this->extensionKey, $this->templateName, $this->language, $siteRootId
551
		);
552

553
554
555
556
557
558
		if ($template === NULL) {
			$template = $this->templateRepository->findOneByTemplate(
				$this->extensionKey, $this->templateName, 'default', $siteRootId
			);
		}

559
560
561
562
563
		// if there is a template, prefer those values
		if ($template) {
			$this->loadTemplateValues($template);
		}

564
		// get default template content from register array
565
		$registerService = GeneralUtility::makeInstance(RegisterService::class);
566
567
		$defaultTemplateContent =
			$registerService->getRegisterArray()[$this->extensionKey][$this->templateName]['templateContent'];
568

569
570
		// If there is no template for this language, use the default template
		if ($template === NULL) {
571
			if ($defaultTemplateContent === NULL) {
572
573
				$templatePath =
					$registerService->getRegisterArray()[$this->extensionKey][$this->templateName]['templatePath'];
574

575
576
				// only standard template file is considered since version 4.1
				$defaultTemplateFile = $templatePath . 'template.html';
Torsten Oppermann's avatar
Torsten Oppermann committed
577
578
				if (file_exists($defaultTemplateFile)) {
					$defaultTemplateContent = file_get_contents($defaultTemplateFile);
579
				} else {
580
581
582
583
584
585
586
587
588
589
590
					// use configured default html template
					/** @var TypoScriptSettingsService $typoScriptSettingsService */
					$typoScriptSettingsService = $this->objectManager->get(TypoScriptSettingsService::class);
					$tsSettings = $typoScriptSettingsService->getSettings(0, 'tx_sgmail');
					$defaultTemplateFile = GeneralUtility::getFileAbsFileName(
						$tsSettings['mail']['defaultHtmlTemplate']
					);

					if (file_exists($defaultTemplateFile)) {
						$defaultTemplateContent = file_get_contents($defaultTemplateFile);
					} else {
591
						return $success;
592
					}
593
				}
594
			}
595

596
		} elseif (filter_var($template->getToAddress(), FILTER_VALIDATE_EMAIL)) {
597
			$this->setToAddresses(trim($template->getToAddress()));
598
599
		}

Torsten Oppermann's avatar
Torsten Oppermann committed
600
601
		if ($isPreview) {
			$previewMarker = [];
602

603
			/** @var array $markerArray */
604
			$markerArray = $registerService->getRegisterArray()[$this->extensionKey][$this->templateName]['marker'];
Torsten Oppermann's avatar
Torsten Oppermann committed
605
			foreach ($markerArray as $marker) {
606
607
608
609
				$markerPath = GeneralUtility::trimExplode('.', $marker['marker']);
				$temporaryMarkerArray = [];
				foreach (array_reverse($markerPath) as $index => $markerPathSegment) {
					if ($index === 0) {
610
611
612
613
						if ($marker['markerLabel']) {
							$markerPathSegment = $marker['markerLabel'];
						}

614
615
616
617
618
619
620
621
						if ($marker['backend_translation_key']) {
							$temporaryMarkerArray[$markerPathSegment] = LocalizationUtility::translate(
								$marker['backend_translation_key'], $marker['extension_key']
							);
						} else {
							$temporaryMarkerArray[$markerPathSegment] = $marker['value'];
						}
					} else {
622
						$temporaryMarkerArray = [$markerPathSegment => $temporaryMarkerArray];
623
					}
624
				}
625
				/** @noinspection SlowArrayOperationsInLoopInspection */
626
				$previewMarker = array_merge_recursive($previewMarker, $temporaryMarkerArray);
Torsten Oppermann's avatar
Torsten Oppermann committed
627
			}
628
			$this->setIgnoreMailQueue(TRUE);
Torsten Oppermann's avatar
Torsten Oppermann committed
629
630
631
			$this->setMarkers($previewMarker);
		}

632
		/** @var StandaloneView $emailView */
633
		$emailView = $this->objectManager->get(StandaloneView::class);
634
		$emailView->assignMultiple($this->markers);
Torsten Oppermann's avatar
Torsten Oppermann committed
635
		$emailView->assign('all_fields', $this->getAllMarker($this->markers));
636

Paul Ilea's avatar
Paul Ilea committed
637
		if ($template !== NULL) {
638
639
640
			$emailView->setTemplateSource(\trim($template->getSubject()));
			$subject = $emailView->render();

641
642
			$emailView->setTemplateSource($template->getContent());
		} else {
643
			$subject = $registerService->getRegisterArray()[$this->extensionKey][$this->templateName]['subject'];
644
645
			if (\is_array($subject)) {
				$subject = \trim(
646
647
					$registerService->getRegisterArray()
					[$this->extensionKey][$this->templateName]['subject'][$this->language]
648
				);
649
			}
650
651
652
653
654
655
656
			if ($subject === NULL && $this->subject !== NULL) {
				$subject = $this->subject;
			}
			if ($subject !== NULL) {
				$emailView->setTemplateSource($subject);
				$subject = $emailView->render();
			}
657
			$emailView->setTemplateSource($defaultTemplateContent);
658
		}
659

Paul Ilea's avatar
Paul Ilea committed
660
		if ($this->subject !== '' && $this->subject !== NULL) {
661
662
663
			$subject = $this->subject;
		}

664
		$this->mailMessage->setSubject($subject);
665

666
667
668
669
670
		// insert <br> tags, but replace every instance of three or more successive breaks with just two.
		$emailBody = $emailView->render();
		$emailBody = nl2br($emailBody);
		$emailBody = preg_replace('/(<br[\s]?[\/]?>[\s]*){3,}/', '<br><br>', $emailBody);

671
672
673
674
675
676
677
678
679
680
681
682
		$mail = $this->addMailToMailQueue(
			$this->extensionKey, $this->templateName, $subject, $emailBody, $this->priority,
			0, 0, $this->language, $siteRootId
		);
		if ($this->ignoreMailQueue) {
			$success = $this->sendMailFromQueue($mail->getUid());
		}

		if ($isPreview) {
			$mailRepository = $this->objectManager->get(MailRepository::class);
			$mailRepository->remove($mail);
			$this->persistenceManager->persistAll();
683
		}
684

685
		return $success;
686
687
688
	}

	/**
689
	 * Adds a new mail to the mail queue.
690
	 *
691
692
	 * @param string $extensionKey
	 * @param string $templateName
693
	 * @param string $subject
694
	 * @param string $emailBody
695
	 * @param int $sendingTime
696
	 * @param int $priority
697
	 * @param int $lastSendingTime
698
	 * @param string $language
699
	 * @param int $pid
700
	 * @return Mail
701
702
	 * @throws \InvalidArgumentException
	 * @throws \BadFunctionCallException
Paul Ilea's avatar
Paul Ilea committed
703
	 * @throws \TYPO3\CMS\Extbase\Persistence\Exception\IllegalObjectTypeException
704
	 * @throws \TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException
705
	 */
706
	private function addMailToMailQueue(
707
		$extensionKey, $templateName, $subject, $emailBody, $priority, $sendingTime = 0,
708
		$lastSendingTime = 0, $language = self::DEFAULT_LANGUAGE, $pid = 0
Torsten Oppermann's avatar
Torsten Oppermann committed
709
	): Mail {
710
		$mail = $this->objectManager->get(Mail::class);
711
		$mail->setPid($pid);
712
713
		$mail->setExtensionKey($extensionKey);
		$mail->setTemplateName($templateName);
714
		$mail->setLanguage($language);
715
		$mail->setBlacklisted(self::isTemplateBlacklisted($extensionKey, $templateName, $pid));
716

717
		$mail->setFromAddress($this->fromAddress);
718
		$mail->setFromName($this->fromName);
719

720
		$mail->setToAddress($this->toAddresses);
721
		$mail->setMailSubject($subject);
722
		$mail->setMailBody($emailBody);
723
		$mail->setPriority($priority);
724
725
		$mail->setBccAddresses($this->bccAddresses);
		$mail->setCcAddresses($this->ccAddresses);
726
		$mail->setSendingTime($sendingTime);
727
		$mail->setLastSendingTime($lastSendingTime);
728
		$mail->setReplyTo($this->replyToAddress);
729
730
731
732
733
		foreach ($this->markers as $marker) {
			if ($marker instanceof FileReference) {
				$mail->addAttachment($marker);
			}
		}
734

735
		$mailRepository = $this->objectManager->get(MailRepository::class);
736
		$mailRepository->add($mail);
737
		$this->persistenceManager->persistAll();
738
		return $mail;
739
	}
740

741
742
743
744
	/**
	 * Send a Mail from the queue, identified by its id
	 *
	 * @param int $uid
745
	 * @return bool
Paul Ilea's avatar
Paul Ilea committed
746
747
	 * @throws \TYPO3\CMS\Extbase\Persistence\Exception\IllegalObjectTypeException
	 * @throws \TYPO3\CMS\Extbase\Persistence\Exception\UnknownObjectException
748
	 * @throws \Exception
749
	 */
Torsten Oppermann's avatar
Torsten Oppermann committed
750
	public function sendMailFromQueue($uid): ?bool {
751
752
		$mailRepository = $this->objectManager->get(MailRepository::class);
		/** @var Mail $mailToSend */
753
		$mailToSend = $mailRepository->findOneByUid($uid);
754

755
		if ($mailToSend && !$mailToSend->getBlacklisted()) {
756
			$this->mailMessage->setBody($mailToSend->getMailBody(), 'text/html');
757
758
759
			$plaintextService = GeneralUtility::makeInstance(PlaintextService::class);
			$plaintextBody = $plaintextService->makePlain($mailToSend->getMailBody());
			$this->mailMessage->addPart($plaintextBody, 'text/plain');
760
761
762
763
764
765
			$toAddresses = trim($mailToSend->getToAddress());
			$addressesArray = GeneralUtility::trimExplode(',', $toAddresses, TRUE);
			if (\count($addressesArray) > 1) {
				$toAddresses = $addressesArray;
			}
			$this->mailMessage->setTo($toAddresses);
766
767
			$this->mailMessage->setFrom($mailToSend->getFromAddress(), $mailToSend->getFromName());
			$this->mailMessage->setSubject($mailToSend->getMailSubject());
768

769
			if ($mailToSend->getBccAddresses()) {
770
771
772
				$this->mailMessage->setBcc(GeneralUtility::trimExplode(',', $mailToSend->getBccAddresses()));
			}

773
			if ($mailToSend->getCcAddresses()) {
774
775
776
777
778
779
				$this->mailMessage->setCc(GeneralUtility::trimExplode(',', $mailToSend->getCcAddresses()));
			}

			if ($mailToSend->getReplyTo()) {
				$this->mailMessage->setReplyTo($mailToSend->getReplyTo());
			}
780
781
782
783
784
785
786
787
788
789
790
791
			$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())
					);
				}
			}
792
			$dateTime = new DateTime();
793
794
795
			if ((int) $mailToSend->getSendingTime() === 0) {
				$mailToSend->setSendingTime($dateTime->getTimestamp());
			}
796
			$mailToSend->setLastSendingTime($dateTime->getTimestamp());
797
798
799
800
801
802
803
			$success = $this->mailMessage->send();
			if ($success) {
				$mailRepository->update($mailToSend);
			} else {
				$this->mailMessage->getFailedRecipients();
			}
			return $success;
804
		}
Torsten Oppermann's avatar
Torsten Oppermann committed
805
806

		return NULL;
807
808
	}

809
810
811
812
813
	/**
	 * use all values from the given template
	 *
	 * @param Template $template
	 */
Torsten Oppermann's avatar
Torsten Oppermann committed
814
	private function loadTemplateValues($template): void {
815
		$fromName = \trim($template->getFromName());
816
817
818
		if ($fromName === '') {
			$fromName = $this->fromName;
		}
819
820
821
822
		if ($fromName === '' && $GLOBALS['TYPO3_CONF_VARS']['MAIL']['defaultMailFromName']) {
			$fromName = $GLOBALS['TYPO3_CONF_VARS']['MAIL']['defaultMailFromName'];
		}

823
		$fromMail = \trim($template->getFromMail());
824
825
826
		if (!filter_var($fromMail, FILTER_VALIDATE_EMAIL)) {
			$fromMail = $this->fromAddress;
		}
827
828
829
830
831
832
833
834
		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);
835
836
837
		$this->setCcAddresses($template->getCc());
		$this->setBccAddresses($template->getBcc());
		$this->setReplyToAddress($template->getReplyTo());
838
		$this->setFromName($fromName);
839
840
841
		$this->setReplyToAddress($template->getReplyTo());
	}

842
843
844
845
846
847
	/**
	 * Get a single variable containing a list of all markers
	 *
	 * @param array $markers
	 * @return string
	 */
848
	private function getAllMarker(array $markers): string {
849
850
851
		$allMarker = '';

		foreach ($markers as $key => $value) {
852
			if (\array_key_exists($key, $this->markerLabels) && $this->markerLabels[$key] !== NULL) {
853
854
				$key = $this->markerLabels[$key];
			}
855

856
			if (\is_string($value)) {
857
				$allMarker .= $key . ': ' . $value . PHP_EOL;
858
			} elseif (\is_array($value)) {
859
				foreach ($value as $innerKey => $innerValue) {
Torsten Oppermann's avatar
Torsten Oppermann committed
860
					$allMarker .= $key . '.' . $innerKey . ': ' . $innerValue . PHP_EOL;
861
				}
862
			} elseif (\is_bool($value)) {
Torsten Oppermann's avatar
Torsten Oppermann committed
863
864
				$valueAsString = $value ? 'true' : 'false';
				$allMarker .= $key . ': ' . $valueAsString . PHP_EOL;
865
866
867
868
			} elseif (\is_object($value)) {
				if (method_exists($value, '__toString')) {
					$allMarker .= $key . ': ' . $value->__toString() . PHP_EOL;
				}
869
870
871
872
873
			}
		}

		return $allMarker;
	}
874
}