‪TYPO3CMS  10.4
EmailFinisher.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
19 
20 use Psr\Http\Message\ServerRequestInterface;
21 use Symfony\Component\Mime\Address;
35 
64 {
65  const ‪FORMAT_PLAINTEXT = 'plaintext';
66  const ‪FORMAT_HTML = 'html';
67 
71  protected ‪$defaultOptions = [
72  'recipientName' => '',
73  'senderName' => '',
74  'addHtmlPart' => true,
75  'attachUploads' => true,
76  ];
77 
84  protected function ‪executeInternal()
85  {
86  $languageBackup = null;
87  // Flexform overrides write strings instead of integers so
88  // we need to cast the string '0' to false.
89  if (
90  isset($this->options['addHtmlPart'])
91  && $this->options['addHtmlPart'] === '0'
92  ) {
93  $this->options['addHtmlPart'] = false;
94  }
95 
96  $subject = $this->‪parseOption('subject');
97  $recipients = $this->‪getRecipients('recipients', 'recipientAddress', 'recipientName');
98  $senderAddress = $this->‪parseOption('senderAddress');
99  $senderAddress = is_string($senderAddress) ? $senderAddress : '';
100  $senderName = $this->‪parseOption('senderName');
101  $senderName = is_string($senderName) ? $senderName : '';
102  $replyToRecipients = $this->‪getRecipients('replyToRecipients', 'replyToAddress');
103  $carbonCopyRecipients = $this->‪getRecipients('carbonCopyRecipients', 'carbonCopyAddress');
104  $blindCarbonCopyRecipients = $this->‪getRecipients('blindCarbonCopyRecipients', 'blindCarbonCopyAddress');
105  $addHtmlPart = $this->‪isHtmlPartAdded();
106  $attachUploads = $this->‪parseOption('attachUploads');
107  $useFluidEmail = $this->‪parseOption('useFluidEmail');
108  $title = $this->‪parseOption('title');
109  $title = is_string($title) && $title !== '' ? $title : $subject;
110 
111  if (empty($subject)) {
112  throw new ‪FinisherException('The option "subject" must be set for the EmailFinisher.', 1327060320);
113  }
114  if (empty($recipients)) {
115  throw new ‪FinisherException('The option "recipients" must be set for the EmailFinisher.', 1327060200);
116  }
117  if (empty($senderAddress)) {
118  throw new ‪FinisherException('The option "senderAddress" must be set for the EmailFinisher.', 1327060210);
119  }
120 
121  $formRuntime = $this->finisherContext->getFormRuntime();
122 
123  $translationService = ‪TranslationService::getInstance();
124  if (is_string($this->options['translation']['language'] ?? null) && $this->options['translation']['language'] !== '') {
125  $languageBackup = $translationService->getLanguage();
126  $translationService->setLanguage($this->options['translation']['language']);
127  }
128 
129  $mail = $useFluidEmail
130  ? $this
131  ->initializeFluidEmail($formRuntime)
133  ->assign('title', $title)
134  : GeneralUtility::makeInstance(MailMessage::class);
135 
136  $mail
137  ->from(new Address($senderAddress, $senderName))
138  ->to(...$recipients)
139  ->subject($subject);
140 
141  if (!empty($replyToRecipients)) {
142  $mail->replyTo(...$replyToRecipients);
143  }
144 
145  if (!empty($carbonCopyRecipients)) {
146  $mail->cc(...$carbonCopyRecipients);
147  }
148 
149  if (!empty($blindCarbonCopyRecipients)) {
150  $mail->bcc(...$blindCarbonCopyRecipients);
151  }
152 
153  if (!$useFluidEmail) {
154  $parts = [
155  [
156  'format' => 'Plaintext',
157  'contentType' => 'text/plain',
158  ],
159  ];
160 
161  if ($addHtmlPart) {
162  $parts[] = [
163  'format' => 'Html',
164  'contentType' => 'text/html',
165  ];
166  }
167 
168  foreach ($parts as $i => $part) {
169  $standaloneView = $this->‪initializeStandaloneView($formRuntime, $part['format']);
170  $message = $standaloneView->render();
171 
172  if ($part['contentType'] === 'text/plain') {
173  $mail->text($message);
174  } else {
175  $mail->html($message);
176  }
177  }
178  }
179 
180  if (!empty($languageBackup)) {
181  $translationService->setLanguage($languageBackup);
182  }
183 
184  $elements = $formRuntime->getFormDefinition()->getRenderablesRecursively();
185 
186  if ($attachUploads) {
187  foreach ($elements as $element) {
188  if (!$element instanceof ‪FileUpload) {
189  continue;
190  }
191  $file = $formRuntime[$element->getIdentifier()];
192  if ($file) {
193  if ($file instanceof ‪FileReference) {
194  $file = $file->getOriginalResource();
195  }
196 
197  $mail->attach($file->getContents(), $file->getName(), $file->getMimeType());
198  }
199  }
200  }
201 
202  $useFluidEmail ? GeneralUtility::makeInstance(Mailer::class)->send($mail) : $mail->send();
203  }
204 
211  protected function ‪initializeStandaloneView(‪FormRuntime $formRuntime, string $format): ‪StandaloneView
212  {
213  $standaloneView = $this->objectManager->get(StandaloneView::class);
214 
215  if (isset($this->options['templatePathAndFilename'])) {
216  // Use local variable instead of augmenting the options to
217  // keep the format intact when sending multi-format mails
218  $templatePathAndFilename = strtr($this->options['templatePathAndFilename'], [
219  '{@format}' => $format
220  ]);
221  $standaloneView->setTemplatePathAndFilename($templatePathAndFilename);
222  } else {
223  if (!isset($this->options['templateName'])) {
224  throw new FinisherException('The option "templateName" must be set for the EmailFinisher.', 1327058829);
225  }
226  // Use local variable instead of augmenting the options to
227  // keep the format intact when sending multi-format mails
228  $templateName = strtr($this->options['templateName'], [
229  '{@format}' => $format
230  ]);
231  $standaloneView->setTemplate($templateName);
232  }
233 
234  $standaloneView->assign('finisherVariableProvider', $this->finisherContext->getFinisherVariableProvider());
235 
236  if (isset($this->options['templateRootPaths']) && is_array($this->options['templateRootPaths'])) {
237  $standaloneView->setTemplateRootPaths($this->options['templateRootPaths']);
238  }
239 
240  if (isset($this->options['partialRootPaths']) && is_array($this->options['partialRootPaths'])) {
241  $standaloneView->setPartialRootPaths($this->options['partialRootPaths']);
242  }
243 
244  if (isset($this->options['layoutRootPaths']) && is_array($this->options['layoutRootPaths'])) {
245  $standaloneView->setLayoutRootPaths($this->options['layoutRootPaths']);
246  }
247 
248  if (isset($this->options['variables'])) {
249  $standaloneView->assignMultiple($this->options['variables']);
250  }
251 
252  $standaloneView->assign('form', $formRuntime);
253  $standaloneView->getRenderingContext()
254  ->getViewHelperVariableContainer()
255  ->addOrUpdate(RenderRenderableViewHelper::class, 'formRuntime', $formRuntime);
256 
257  return $standaloneView;
258  }
259 
260  protected function ‪initializeFluidEmail(‪FormRuntime $formRuntime): ‪FluidEmail
261  {
262  $templateConfiguration = ‪$GLOBALS['TYPO3_CONF_VARS']['MAIL'];
263 
264  if (is_array($this->options['templateRootPaths'] ?? null)) {
265  $templateConfiguration['templateRootPaths'] = array_replace_recursive(
266  $templateConfiguration['templateRootPaths'],
267  $this->options['templateRootPaths']
268  );
269  ksort($templateConfiguration['templateRootPaths']);
270  }
271 
272  if (is_array($this->options['partialRootPaths'] ?? null)) {
273  $templateConfiguration['partialRootPaths'] = array_replace_recursive(
274  $templateConfiguration['partialRootPaths'],
275  $this->options['partialRootPaths']
276  );
277  ksort($templateConfiguration['partialRootPaths']);
278  }
279 
280  if (is_array($this->options['layoutRootPaths'] ?? null)) {
281  $templateConfiguration['layoutRootPaths'] = array_replace_recursive(
282  $templateConfiguration['layoutRootPaths'],
283  $this->options['layoutRootPaths']
284  );
285  ksort($templateConfiguration['layoutRootPaths']);
286  }
287 
288  $fluidEmail = GeneralUtility::makeInstance(
289  FluidEmail::class,
290  GeneralUtility::makeInstance(TemplatePaths::class, $templateConfiguration)
291  );
292 
293  if (!isset($this->options['templateName']) || $this->options['templateName'] === '') {
294  throw new ‪FinisherException('The option "templateName" must be set to use FluidEmail.', 1599834020);
295  }
296 
297  // Migrate old template name to default FluidEmail name
298  if ($this->options['templateName'] === '{@format}.html') {
299  $this->options['templateName'] = 'Default';
300  }
301 
302  // Set the PSR-7 request object if available
303  if ((‪$GLOBALS['TYPO3_REQUEST'] ?? null) instanceof ServerRequestInterface) {
304  $fluidEmail->setRequest(‪$GLOBALS['TYPO3_REQUEST']);
305  }
306 
307  $fluidEmail
308  ->setTemplate($this->options['templateName'])
309  ->assignMultiple([
310  'finisherVariableProvider' => $this->finisherContext->getFinisherVariableProvider(),
311  'form' => $formRuntime
312  ]);
313 
314  if (is_array($this->options['variables'] ?? null)) {
315  $fluidEmail->assignMultiple($this->options['variables']);
316  }
317 
318  $fluidEmail
319  ->getViewHelperVariableContainer()
320  ->addOrUpdate(RenderRenderableViewHelper::class, 'formRuntime', $formRuntime);
321 
322  return $fluidEmail;
323  }
324 
335  protected function ‪getRecipients(
336  string $listOption,
337  string $singleAddressOption,
338  string $singleAddressNameOption = null
339  ): array {
340  $recipients = $this->‪parseOption($listOption);
341  $singleAddress = $this->‪parseOption($singleAddressOption);
342  $singleAddressName = '';
343 
344  $recipients = $recipients ?? [];
345 
346  if (!empty($singleAddress)) {
347  trigger_error(sprintf(
348  'EmailFinisher option "%s" is deprecated and will be removed in TYPO3 v11.0. Use "%s" instead.',
349  $singleAddressOption,
350  $listOption
351  ), E_USER_DEPRECATED);
352 
353  if (!empty($singleAddressNameOption)) {
354  trigger_error(sprintf(
355  'EmailFinisher option "%s" is deprecated and will be removed in TYPO3 v11.0. Use "%s" instead.',
356  $singleAddressNameOption,
357  $listOption
358  ), E_USER_DEPRECATED);
359  $singleAddressName = $this->‪parseOption($singleAddressNameOption);
360  }
361 
362  $recipients[$singleAddress] = $singleAddressName ?: '';
363  }
364 
365  $addresses = [];
366  foreach ($recipients as $address => $name) {
368  $address = $name;
369  $name = '';
370  }
371  // Drop entries without mail address
372  if (empty($address)) {
373  continue;
374  }
375  $addresses[] = new Address($address, $name);
376  }
377  return $addresses;
378  }
379 
387  protected function ‪isHtmlPartAdded(): bool
388  {
389  $format = $this->‪parseOption('format');
390 
391  if ($format !== null) {
392  trigger_error(
393  'Usage of format option in form email finisher is deprecated - use addHtmlPart instead.',
394  E_USER_DEPRECATED
395  );
396  }
397 
398  // FORMAT_HTML was the default value for "format", so
399  // FORMAT_PLAINTEXT must have been set intentionally
400  if ($format === self::FORMAT_PLAINTEXT) {
401  return false;
402  }
403 
404  return $this->‪parseOption('addHtmlPart') ? true : false;
405  }
406 }
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime
Definition: FormRuntime.php:103
‪TYPO3\CMS\Form\Service\TranslationService\getInstance
‪static TranslationService getInstance()
Definition: TranslationService.php:83
‪TYPO3\CMS\Fluid\View\TemplatePaths
Definition: TemplatePaths.php:35
‪TYPO3\CMS\Core\Utility\MathUtility\canBeInterpretedAsInteger
‪static bool canBeInterpretedAsInteger($var)
Definition: MathUtility.php:74
‪TYPO3\CMS\Form\Service\TranslationService
Definition: TranslationService.php:44
‪TYPO3\CMS\Core\Mail\FluidEmail\FORMAT_BOTH
‪const FORMAT_BOTH
Definition: FluidEmail.php:38
‪TYPO3\CMS\Core\Mail\MailMessage
Definition: MailMessage.php:28
‪TYPO3\CMS\Form\Domain\Finishers\EmailFinisher\getRecipients
‪array getRecipients(string $listOption, string $singleAddressOption, string $singleAddressNameOption=null)
Definition: EmailFinisher.php:334
‪TYPO3\CMS\Form\Domain\Finishers\EmailFinisher\isHtmlPartAdded
‪bool isHtmlPartAdded()
Definition: EmailFinisher.php:386
‪TYPO3\CMS\Form\Domain\Finishers
Definition: AbstractFinisher.php:22
‪TYPO3\CMS\Form\Domain\Finishers\EmailFinisher\FORMAT_HTML
‪const FORMAT_HTML
Definition: EmailFinisher.php:66
‪TYPO3\CMS\Form\Domain\Finishers\EmailFinisher\initializeFluidEmail
‪initializeFluidEmail(FormRuntime $formRuntime)
Definition: EmailFinisher.php:259
‪TYPO3\CMS\Form\Domain\Finishers\AbstractFinisher
Definition: AbstractFinisher.php:41
‪TYPO3\CMS\Core\Mail\FluidEmail
Definition: FluidEmail.php:35
‪TYPO3\CMS\Form\Domain\Finishers\Exception\FinisherException
Definition: FinisherException.php:26
‪TYPO3\CMS\Form\ViewHelpers\RenderRenderableViewHelper
Definition: RenderRenderableViewHelper.php:41
‪TYPO3\CMS\Core\Mail\Mailer
Definition: Mailer.php:38
‪TYPO3\CMS\Core\Mail\FluidEmail\FORMAT_PLAIN
‪const FORMAT_PLAIN
Definition: FluidEmail.php:37
‪TYPO3\CMS\Extbase\Domain\Model\FileReference
Definition: FileReference.php:28
‪TYPO3\CMS\Fluid\View\StandaloneView
Definition: StandaloneView.php:34
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime
Definition: FormSession.php:18
‪TYPO3\CMS\Form\Domain\Finishers\EmailFinisher\$defaultOptions
‪array $defaultOptions
Definition: EmailFinisher.php:70
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:5
‪TYPO3\CMS\Form\Domain\Finishers\EmailFinisher
Definition: EmailFinisher.php:64
‪TYPO3\CMS\Core\Utility\MathUtility
Definition: MathUtility.php:22
‪TYPO3\CMS\Form\Domain\Finishers\AbstractFinisher\parseOption
‪string array null parseOption(string $optionName)
Definition: AbstractFinisher.php:161
‪TYPO3\CMS\Form\Domain\Finishers\EmailFinisher\initializeStandaloneView
‪StandaloneView initializeStandaloneView(FormRuntime $formRuntime, string $format)
Definition: EmailFinisher.php:210
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:46
‪TYPO3\CMS\Form\Domain\Model\FormElements\FileUpload
Definition: FileUpload.php:28
‪TYPO3\CMS\Form\Domain\Finishers\EmailFinisher\FORMAT_PLAINTEXT
‪const FORMAT_PLAINTEXT
Definition: EmailFinisher.php:65
‪TYPO3\CMS\Form\Domain\Finishers\EmailFinisher\executeInternal
‪executeInternal()
Definition: EmailFinisher.php:83