templateName = $templateName;
$this->extensionKey = $extensionKey;
$this->markers = $markers;
$this->markerLabels = $markerLabels;
/** @var ObjectManager objectManager */
$this->objectManager = GeneralUtility::makeInstance(ObjectManager::class);
$this->mailMessage = $this->objectManager->get(MailMessage::class);
$typoScriptSettingsService = $this->objectManager->get(TypoScriptSettingsService::class);
$tsSettings = $typoScriptSettingsService->getSettings(0, 'tx_sgmail');
$this->templateRepository = $this->objectManager->get(TemplateRepository::class);
$this->persistenceManager = $this->objectManager->get(PersistenceManager::class);
// use defaultMailFromAddress if it is provided in LocalConfiguration.php; use the sg_mail TS setting as fallback
if (filter_var($GLOBALS['TYPO3_CONF_VARS']['MAIL']['defaultMailFromAddress'], FILTER_VALIDATE_EMAIL)) {
$this->fromAddress = $GLOBALS['TYPO3_CONF_VARS']['MAIL']['defaultMailFromAddress'];
} else {
$this->fromAddress = $tsSettings['mail']['default']['from'];
if (!filter_var($tsSettings['mail']['default']['from'], FILTER_VALIDATE_EMAIL)) {
$this->fromAddress = 'noreply@example.org';
} else {
$this->fromAddress = $tsSettings['mail']['default']['from'];
}
}
$this->mailMessage->setFrom($this->fromAddress);
$this->bccAddresses = GeneralUtility::trimExplode(',', $tsSettings['mail']['default']['bcc']);
$this->ccAddresses = GeneralUtility::trimExplode(',', $tsSettings['mail']['default']['cc']);
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]);
}
}
if (\count($this->bccAddresses) > 0) {
$this->mailMessage->setBcc($this->bccAddresses);
}
if (\count($this->ccAddresses) > 0) {
$this->mailMessage->setCc($this->ccAddresses);
}
}
/**
* @param string $fromName
*/
public function setFromName($fromName): void {
$this->fromName = $fromName;
}
/**
* Provides translation for the marker data type
*
* @param string $markerType
*/
public static function getReadableMarkerType($markerType): void {
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;
foreach($markers as $key => $currentMarker) {
if (!isset($currentMarker['markerLabel'])) {
continue;
}
$this->markerLabels[$key] = $currentMarker['markerLabel'];
}
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;
}
/**
* Add a file resource as attachment
*
* @param FileInterface|FileReference $file
* @return MailTemplateService
* @throws \TYPO3\CMS\Core\Resource\Exception\ResourceDoesNotExistException
*/
public function addFileResourceAttachment($file): MailTemplateService {
if ($file instanceof FileReference) {
$file = $file->getOriginalResource()->getOriginalFile();
}
$fileReference = $this->objectManager->get(FileReference::class);
$resourceFactory = $this->objectManager->get(ResourceFactory::class);
$falFileReference = $resourceFactory->createFileReferenceObject(
[
'uid_local' => $file->getUid(),
'uid_foreign' => uniqid('NEW_', TRUE),
'uid' => uniqid('NEW_', TRUE),
'crop' => NULL,
]
);
$fileReference->setOriginalResource($falFileReference);
$this->markers[] = $fileReference;
/** @noinspection PhpParamsInspection */
$this->addAttachment($file->getContents(), $file->getName(), $file->getMimeType());
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
*/
public function setSubject(string $subject): void {
$this->subject = $subject;
}
/**
* 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'): array {
$languagePath = 'LLL:EXT:' . $extensionKey . '/Resources/Private/Language/locallang.xlf:' . $translationKey;
// 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;
}
/**
* Send the Email
*
* @param bool $isPreview
* @return bool email was sent or added to mail queue successfully?
* @throws \TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException
* @throws \InvalidArgumentException
* @throws \BadFunctionCallException
* @throws \TYPO3\CMS\Extbase\Persistence\Exception\IllegalObjectTypeException
* @throws \Exception
*/
public function sendEmail($isPreview = FALSE): bool {
$success = FALSE;
if (TYPO3_MODE === 'FE') {
/** @var TypoScriptFrontendController $typoscriptFrontendController */
$typoscriptFrontendController = $GLOBALS['TSFE'];
$pageUid = (int) $typoscriptFrontendController->id;
} else {
$pageUid = (int) GeneralUtility::_GP('id');
}
if ($this->pid) {
$pageUid = $this->pid;
}
if ($pageUid === 0) {
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable(
'pages'
);
$rootPageRows = $queryBuilder->select('*')
->from('pages')
->where(
$queryBuilder->expr()->eq(
'is_siteroot', 1
)
)
->andWhere(
$queryBuilder->expr()->eq(
'hidden', 0
)
)
->execute()->fetchAll();
if ($rootPageRows && \count($rootPageRows)) {
$pageUid = (int) $rootPageRows[0]['uid'];
}
}
$siteRootId = BackendService::getSiteRoot($pageUid);
$isTemplateBlacklisted = self::isTemplateBlacklisted($this->extensionKey, $this->templateName, $siteRootId);
if ($isTemplateBlacklisted) {
// @TODO: This needs to be changed, because if the template is blacklisted, the email can not be sent
$success = TRUE;
return $success;
}
/** @var Template $template */
$template = $this->templateRepository->findOneByTemplate(
$this->extensionKey, $this->templateName, $this->language, $siteRootId
);
if ($template === NULL) {
$template = $this->templateRepository->findOneByTemplate(
$this->extensionKey, $this->templateName, 'default', $siteRootId
);
}
// if there is a template, prefer those values
if ($template) {
$this->loadTemplateValues($template);
}
// get default template content from register array
$registerService = GeneralUtility::makeInstance(RegisterService::class);
$defaultTemplateContent =
$registerService->getRegisterArray()[$this->extensionKey][$this->templateName]['templateContent'];
// If there is no template for this language, use the default template
if ($template === NULL) {
if ($defaultTemplateContent === NULL) {
$templatePath =
$registerService->getRegisterArray()[$this->extensionKey][$this->templateName]['templatePath'];
// only standard template file is considered since version 4.1
$defaultTemplateFile = $templatePath . 'template.html';
if (file_exists($defaultTemplateFile)) {
$defaultTemplateContent = file_get_contents($defaultTemplateFile);
} else {
// 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 {
return $success;
}
}
}
} elseif (filter_var($template->getToAddress(), FILTER_VALIDATE_EMAIL)) {
$this->setToAddresses(trim($template->getToAddress()));
}
if ($isPreview) {
$previewMarker = [];
/** @var array $markerArray */
$markerArray = $registerService->getRegisterArray()[$this->extensionKey][$this->templateName]['marker'];
foreach ($markerArray as $marker) {
$markerPath = GeneralUtility::trimExplode('.', $marker['marker']);
$temporaryMarkerArray = [];
foreach (array_reverse($markerPath) as $index => $markerPathSegment) {
if ($index === 0) {
if ($marker['markerLabel']) {
$markerPathSegment = $marker['markerLabel'];
}
if ($marker['backend_translation_key']) {
$temporaryMarkerArray[$markerPathSegment] = LocalizationUtility::translate(
$marker['backend_translation_key'], $marker['extension_key']
);
} else {
$temporaryMarkerArray[$markerPathSegment] = $marker['value'];
}
} else {
$temporaryMarkerArray = [$markerPathSegment => $temporaryMarkerArray];
}
}
/** @noinspection SlowArrayOperationsInLoopInspection */
$previewMarker = array_merge_recursive($previewMarker, $temporaryMarkerArray);
}
$this->setIgnoreMailQueue(TRUE);
$this->setMarkers($previewMarker);
}
/** @var StandaloneView $emailView */
$emailView = $this->objectManager->get(StandaloneView::class);
$emailView->assignMultiple($this->markers);
$emailView->assign('all_fields', $this->getAllMarker($this->markers));
if ($template !== NULL) {
$emailView->setTemplateSource(\trim($template->getSubject()));
$subject = $emailView->render();
$emailView->setTemplateSource($template->getContent());
} else {
$subject = $registerService->getRegisterArray()[$this->extensionKey][$this->templateName]['subject'];
if (\is_array($subject)) {
$subject = \trim(
$registerService->getRegisterArray()
[$this->extensionKey][$this->templateName]['subject'][$this->language]
);
}
if ($subject === NULL && $this->subject !== NULL) {
$subject = $this->subject;
}
if ($subject !== NULL) {
$emailView->setTemplateSource($subject);
$subject = $emailView->render();
}
$emailView->setTemplateSource($defaultTemplateContent);
}
if ($this->subject !== '' && $this->subject !== NULL) {
$subject = $this->subject;
}
$this->mailMessage->setSubject($subject);
// insert
tags, but replace every instance of three or more successive breaks with just two.
$emailBody = $emailView->render();
$emailBody = nl2br($emailBody);
$emailBody = preg_replace('/(
[\s]*){3,}/', '
', $emailBody);
$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();
}
return $success;
}
/**
* Adds a new mail to the mail queue.
*
* @param string $extensionKey
* @param string $templateName
* @param string $subject
* @param string $emailBody
* @param int $sendingTime
* @param int $priority
* @param int $lastSendingTime
* @param string $language
* @param int $pid
* @return Mail
* @throws \InvalidArgumentException
* @throws \BadFunctionCallException
* @throws \TYPO3\CMS\Extbase\Persistence\Exception\IllegalObjectTypeException
* @throws \TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException
*/
private function addMailToMailQueue(
$extensionKey, $templateName, $subject, $emailBody, $priority, $sendingTime = 0,
$lastSendingTime = 0, $language = self::DEFAULT_LANGUAGE, $pid = 0
): Mail {
$mail = $this->objectManager->get(Mail::class);
$mail->setPid($pid);
$mail->setExtensionKey($extensionKey);
$mail->setTemplateName($templateName);
$mail->setLanguage($language);
$mail->setBlacklisted(self::isTemplateBlacklisted($extensionKey, $templateName, $pid));
$mail->setFromAddress($this->fromAddress);
$mail->setFromName($this->fromName);
$mail->setToAddress($this->toAddresses);
$mail->setMailSubject($subject);
$mail->setMailBody($emailBody);
$mail->setPriority($priority);
$mail->setBccAddresses($this->bccAddresses);
$mail->setCcAddresses($this->ccAddresses);
$mail->setSendingTime($sendingTime);
$mail->setLastSendingTime($lastSendingTime);
$mail->setReplyTo($this->replyToAddress);
foreach ($this->markers as $marker) {
if ($marker instanceof FileReference) {
$mail->addAttachment($marker);
}
}
$mailRepository = $this->objectManager->get(MailRepository::class);
$mailRepository->add($mail);
$this->persistenceManager->persistAll();
return $mail;
}
/**
* Send a Mail from the queue, identified by its id
*
* @param int $uid
* @return bool
* @throws \TYPO3\CMS\Extbase\Persistence\Exception\IllegalObjectTypeException
* @throws \TYPO3\CMS\Extbase\Persistence\Exception\UnknownObjectException
* @throws \Exception
*/
public function sendMailFromQueue($uid): ?bool {
$mailRepository = $this->objectManager->get(MailRepository::class);
/** @var Mail $mailToSend */
$mailToSend = $mailRepository->findOneByUid($uid);
if ($mailToSend && !$mailToSend->getBlacklisted()) {
$this->mailMessage->setBody($mailToSend->getMailBody(), 'text/html');
$plaintextService = GeneralUtility::makeInstance(PlaintextService::class);
$plaintextBody = $plaintextService->makePlain($mailToSend->getMailBody());
$this->mailMessage->addPart($plaintextBody, 'text/plain');
$toAddresses = trim($mailToSend->getToAddress());
$addressesArray = GeneralUtility::trimExplode(',', $toAddresses, TRUE);
if (\count($addressesArray) > 1) {
$toAddresses = $addressesArray;
}
$this->mailMessage->setTo($toAddresses);
$this->mailMessage->setFrom($mailToSend->getFromAddress(), $mailToSend->getFromName());
$this->mailMessage->setSubject($mailToSend->getMailSubject());
if ($mailToSend->getBccAddresses()) {
$this->mailMessage->setBcc(GeneralUtility::trimExplode(',', $mailToSend->getBccAddresses()));
}
if ($mailToSend->getCcAddresses()) {
$this->mailMessage->setCc(GeneralUtility::trimExplode(',', $mailToSend->getCcAddresses()));
}
if ($mailToSend->getReplyTo()) {
$this->mailMessage->setReplyTo($mailToSend->getReplyTo());
}
$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())
);
}
}
$dateTime = new DateTime();
if ((int) $mailToSend->getSendingTime() === 0) {
$mailToSend->setSendingTime($dateTime->getTimestamp());
}
$mailToSend->setLastSendingTime($dateTime->getTimestamp());
$success = $this->mailMessage->send();
if ($success) {
$mailRepository->update($mailToSend);
} else {
$this->mailMessage->getFailedRecipients();
}
return $success;
}
return NULL;
}
/**
* use all values from the given template
*
* @param Template $template
*/
private function loadTemplateValues($template): void {
$fromName = \trim($template->getFromName());
if ($fromName === '' && $GLOBALS['TYPO3_CONF_VARS']['MAIL']['defaultMailFromName']) {
$fromName = $GLOBALS['TYPO3_CONF_VARS']['MAIL']['defaultMailFromName'];
}
$fromMail = \trim($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);
$this->setCcAddresses($template->getCc());
$this->setBccAddresses($template->getBcc());
$this->setReplyToAddress($template->getReplyTo());
$this->setFromName($fromName);
$this->setReplyToAddress($template->getReplyTo());
}
/**
* Get a single variable containing a list of all markers
*
* @param array $markers
* @return string
*/
private function getAllMarker(array $markers): string {
$allMarker = '';
foreach ($markers as $key => $value) {
if (\array_key_exists($key, $this->markerLabels) && $this->markerLabels[$key] !== NULL) {
$key = $this->markerLabels[$key];
}
if (\is_string($value)) {
$allMarker .= $key . ': ' . $value . PHP_EOL;
} elseif (\is_array($value)) {
foreach ($value as $innerKey => $innerValue) {
$allMarker .= $key . '.' . $innerKey . ': ' . $innerValue . PHP_EOL;
}
} elseif (\is_bool($value)) {
$valueAsString = $value ? 'true' : 'false';
$allMarker .= $key . ': ' . $valueAsString . PHP_EOL;
} elseif (\is_object($value)) {
if (method_exists($value, '__toString')) {
$allMarker .= $key . ': ' . $value->__toString() . PHP_EOL;
}
}
}
return $allMarker;
}
}