From 42b591bc65e053b5a40144b0d7832fa703b858e6 Mon Sep 17 00:00:00 2001
From: Kevin Ditscheid <kevin.ditscheid@sgalinski.de>
Date: Thu, 24 May 2018 14:32:37 +0200
Subject: [PATCH] [FEATURE] Add a plaintext version of the body text

We use a PlaintextService to convert the HTML body to a plaintext
version of it to be able to send it alongside the mail
---
 Classes/Command/SendMailCommandController.php |   5 +
 Classes/Service/MailTemplateService.php       |   8 +-
 Classes/Service/PlaintextService.php          | 167 ++++++++++++++++++
 3 files changed, 179 insertions(+), 1 deletion(-)
 create mode 100644 Classes/Service/PlaintextService.php

diff --git a/Classes/Command/SendMailCommandController.php b/Classes/Command/SendMailCommandController.php
index e1c134d1..e751533c 100644
--- a/Classes/Command/SendMailCommandController.php
+++ b/Classes/Command/SendMailCommandController.php
@@ -27,6 +27,7 @@ namespace SGalinski\SgMail\Command;
  ***************************************************************/
 
 use SGalinski\SgMail\Domain\Model\Mail;
+use SGalinski\SgMail\Service\PlaintextService;
 use TYPO3\CMS\Core\Mail\MailMessage;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Extbase\Mvc\Controller\CommandController;
@@ -85,7 +86,11 @@ class SendMailCommandController extends CommandController {
 			if (count($bccAddresses)) {
 				$mailMessage->setBcc($bccAddresses);
 			}
+
 			$mailMessage->setBody($mailBody, 'text/html');
+            $plaintextService = GeneralUtility::makeInstance(PlaintextService::class);
+            $plaintextBody = $plaintextService->makePlain($mailBody);
+            $mailMessage->addPart($plaintextBody, 'text/plain');
 
 			try {
 				$mailMessage->send();
diff --git a/Classes/Service/MailTemplateService.php b/Classes/Service/MailTemplateService.php
index 8752bf3c..602a6bbf 100644
--- a/Classes/Service/MailTemplateService.php
+++ b/Classes/Service/MailTemplateService.php
@@ -355,12 +355,15 @@ class MailTemplateService {
 		// 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);
+
 		$isTemplateBlacklisted = self::isTemplateBlacklisted(
 			$this->extensionKey, $this->templateName, $siteRootId
 		);
 		if ($this->ignoreMailQueue && !$isTemplateBlacklisted) {
-
 			$this->mailMessage->setBody($emailBody, 'text/html');
+            $plaintextService = GeneralUtility::makeInstance(PlaintextService::class);
+            $plainTextBody = $plaintextService->makePlain($emailBody);
+            $this->mailMessage->addPart($plainTextBody, 'text/plain');
 			$this->mailMessage->send();
 			$dateTime = new DateTime();
 			$currentTimestamp = $dateTime->getTimestamp();
@@ -444,6 +447,9 @@ class MailTemplateService {
 
 		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');
 			$this->mailMessage->setTo(trim($mailToSend->getToAddress()));
 			$this->mailMessage->setFrom($mailToSend->getFromAddress(), $mailToSend->getFromName());
 			$this->mailMessage->setSubject($mailToSend->getMailSubject());
diff --git a/Classes/Service/PlaintextService.php b/Classes/Service/PlaintextService.php
new file mode 100644
index 00000000..6ce872f9
--- /dev/null
+++ b/Classes/Service/PlaintextService.php
@@ -0,0 +1,167 @@
+<?php
+/**
+ * Copyright notice
+ *
+ * (c) in2code <info@in2code.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 2 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!
+ */
+
+declare(strict_types=1);
+namespace SGalinski\SgMail\Service;
+
+/**
+ * Class PlaintextService
+ */
+class PlaintextService
+{
+
+    /**
+     * Function makePlain() removes html tags and add linebreaks
+     *        Easy generate a plain email bodytext from a html bodytext
+     *
+     * @param string $content HTML Mail bodytext
+     * @return string $content
+     */
+    public function makePlain($content)
+    {
+        $content = $this->removeInvisibleElements($content);
+        $content = $this->removeLinebreaksAndTabs($content);
+        $content = $this->addLineBreaks($content);
+        $content = $this->addSpaceToTableCells($content);
+        $content = $this->extractLinkForPlainTextContent($content);
+        $content = $this->removeTags($content);
+        $array = [
+            '<br >',
+            '<br>',
+            '<br/>',
+            '<br />'
+        ];
+        return trim(str_replace($array, PHP_EOL, $content));
+    }
+
+    /**
+     * Remove all invisible elements
+     *
+     * @param string $content
+     * @return string
+     */
+    protected function removeInvisibleElements($content)
+    {
+        $content = preg_replace(
+            [
+                '/<head[^>]*?>.*?<\/head>/siu',
+                '/<style[^>]*?>.*?<\/style>/siu',
+                '/<script[^>]*?>.*?<\/script>/siu',
+                '/<object[^>]*?>.*?<\/object>/siu',
+                '/<embed[^>]*?>.*?<\/embed>/siu',
+                '/<applet[^>]*?>.*?<\/applet>/siu',
+                '/<noframes[^>]*?>.*?<\/noframes>/siu',
+                '/<noscript[^>]*?>.*?<\/noscript>/siu',
+                '/<noembed[^>]*?>.*?<\/noembed>/siu',
+            ],
+            [
+                '', '', '', '', '', '', '', '', ''
+            ],
+            $content
+        );
+        return $content;
+    }
+
+    /**
+     * Remove linebreaks and tabs
+     *
+     * @param string $content
+     * @return string
+     */
+    protected function removeLinebreaksAndTabs($content)
+    {
+        $content = trim(str_replace(["\n", "\r", "\t"], '', $content));
+        return $content;
+    }
+
+    /**
+     * add linebreaks on some parts (</p> => </p><br />)
+     *
+     * @param string $content
+     * @return array
+     */
+    protected function addLineBreaks($content)
+    {
+        $tags2LineBreaks = [
+            '</p>',
+            '</tr>',
+            '<ul>',
+            '</li>',
+            '</h1>',
+            '</h2>',
+            '</h3>',
+            '</h4>',
+            '</h5>',
+            '</h6>',
+            '</div>',
+            '</legend>',
+            '</fieldset>',
+            '</dd>',
+            '</dt>'
+        ];
+        return str_replace($tags2LineBreaks, '</p><br />', $content);
+    }
+
+    /**
+     * Add a space character to a table cell
+     *
+     * @param string $content
+     * @return string
+     */
+    protected function addSpaceToTableCells($content)
+    {
+        return str_replace(['</td>', '</th>'], '</td> ', $content);
+    }
+
+    /**
+     * Remove all tags but keep br and address
+     *
+     * @param string $content
+     * @return string
+     */
+    protected function removeTags($content)
+    {
+        return strip_tags($content, '<br><address>');
+    }
+
+    /**
+     * Extract uri from href attributes and decode it
+     *
+     *  replace links
+     *      <a href="xyz">LINK</a>
+     *      ->
+     *      LINK [xyz]
+     *
+     * @param string $content
+     * @return string
+     */
+    protected function extractLinkForPlainTextContent($content)
+    {
+        $pattern = '/<a[^>]+href\s*=\s*["\']([^"\']+)["\'][^>]*>(.*?)<\/a>/misu';
+        return preg_replace_callback($pattern, function ($matches) {
+            return $matches[2] . ' [' . htmlspecialchars_decode($matches[1]) . ']';
+        }, $content);
+    }
+}
-- 
GitLab