瀏覽代碼

Merge pull request #35876 from bennet0496/patch-mail-header

Adding option to set Auto-Submitted email header
Joas Schilling 1 年之前
父節點
當前提交
348454cb91

+ 2 - 0
apps/dav/lib/CalDAV/Reminder/NotificationProvider/EmailProvider.php

@@ -37,6 +37,7 @@ use OCP\IL10N;
 use OCP\IURLGenerator;
 use OCP\IUser;
 use OCP\L10N\IFactory as L10NFactory;
+use OCP\Mail\Headers\AutoSubmitted;
 use OCP\Mail\IEMailTemplate;
 use OCP\Mail\IMailer;
 use Psr\Log\LoggerInterface;
@@ -130,6 +131,7 @@ class EmailProvider extends AbstractProvider {
 				}
 				$message->setTo([$emailAddress]);
 				$message->useTemplate($template);
+				$message->setAutoSubmitted(AutoSubmitted::VALUE_AUTO_GENERATED);
 
 				try {
 					$failed = $this->mailer->send($message);

+ 2 - 0
apps/settings/lib/Mailer/NewUserMailHelper.php

@@ -35,6 +35,7 @@ use OCP\IConfig;
 use OCP\IURLGenerator;
 use OCP\IUser;
 use OCP\L10N\IFactory;
+use OCP\Mail\Headers\AutoSubmitted;
 use OCP\Mail\IEMailTemplate;
 use OCP\Mail\IMailer;
 use OCP\Security\ICrypto;
@@ -181,6 +182,7 @@ class NewUserMailHelper {
 		$message->setTo([$email => $user->getDisplayName()]);
 		$message->setFrom([$this->fromAddress => $this->themingDefaults->getName()]);
 		$message->useTemplate($emailTemplate);
+		$message->setAutoSubmitted(AutoSubmitted::VALUE_AUTO_GENERATED);
 		$this->mailer->send($message);
 	}
 }

+ 5 - 0
apps/settings/tests/Mailer/NewUserMailHelperTest.php

@@ -42,6 +42,7 @@ use OCP\IL10N;
 use OCP\IURLGenerator;
 use OCP\IUser;
 use OCP\L10N\IFactory;
+use OCP\Mail\Headers\AutoSubmitted;
 use OCP\Mail\IEMailTemplate;
 use OCP\Mail\IMailer;
 use OCP\Security\ICrypto;
@@ -867,6 +868,10 @@ EOF;
 			->expects($this->once())
 			->method('useTemplate')
 			->with($emailTemplate);
+		$message
+			->expects($this->once())
+			->method('setAutoSubmitted')
+			->with(AutoSubmitted::VALUE_AUTO_GENERATED);
 		$this->defaults
 			->expects($this->once())
 			->method('getName')

+ 1 - 0
lib/composer/composer/autoload_classmap.php

@@ -479,6 +479,7 @@ return array(
     'OCP\\Log\\IWriter' => $baseDir . '/lib/public/Log/IWriter.php',
     'OCP\\Log\\RotationTrait' => $baseDir . '/lib/public/Log/RotationTrait.php',
     'OCP\\Mail\\Events\\BeforeMessageSent' => $baseDir . '/lib/public/Mail/Events/BeforeMessageSent.php',
+    'OCP\\Mail\\Headers\\AutoSubmitted' => $baseDir . '/lib/public/Mail/Headers/AutoSubmitted.php',
     'OCP\\Mail\\IAttachment' => $baseDir . '/lib/public/Mail/IAttachment.php',
     'OCP\\Mail\\IEMailTemplate' => $baseDir . '/lib/public/Mail/IEMailTemplate.php',
     'OCP\\Mail\\IMailer' => $baseDir . '/lib/public/Mail/IMailer.php',

+ 10 - 17
lib/composer/composer/autoload_real.php

@@ -31,25 +31,18 @@ class ComposerAutoloaderInit749170dad3f5e7f9ca158f5a9f04f6a2
 
         $loader->register(true);
 
-        $includeFiles = \Composer\Autoload\ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2::$files;
-        foreach ($includeFiles as $fileIdentifier => $file) {
-            composerRequire749170dad3f5e7f9ca158f5a9f04f6a2($fileIdentifier, $file);
+        $filesToLoad = \Composer\Autoload\ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2::$files;
+        $requireFile = static function ($fileIdentifier, $file) {
+            if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
+                $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
+
+                require $file;
+            }
+        };
+        foreach ($filesToLoad as $fileIdentifier => $file) {
+            ($requireFile)($fileIdentifier, $file);
         }
 
         return $loader;
     }
 }
-
-/**
- * @param string $fileIdentifier
- * @param string $file
- * @return void
- */
-function composerRequire749170dad3f5e7f9ca158f5a9f04f6a2($fileIdentifier, $file)
-{
-    if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
-        $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
-
-        require $file;
-    }
-}

+ 1 - 0
lib/composer/composer/autoload_static.php

@@ -512,6 +512,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
         'OCP\\Log\\IWriter' => __DIR__ . '/../../..' . '/lib/public/Log/IWriter.php',
         'OCP\\Log\\RotationTrait' => __DIR__ . '/../../..' . '/lib/public/Log/RotationTrait.php',
         'OCP\\Mail\\Events\\BeforeMessageSent' => __DIR__ . '/../../..' . '/lib/public/Mail/Events/BeforeMessageSent.php',
+        'OCP\\Mail\\Headers\\AutoSubmitted' => __DIR__ . '/../../..' . '/lib/public/Mail/Headers/AutoSubmitted.php',
         'OCP\\Mail\\IAttachment' => __DIR__ . '/../../..' . '/lib/public/Mail/IAttachment.php',
         'OCP\\Mail\\IEMailTemplate' => __DIR__ . '/../../..' . '/lib/public/Mail/IEMailTemplate.php',
         'OCP\\Mail\\IMailer' => __DIR__ . '/../../..' . '/lib/public/Mail/IMailer.php',

+ 38 - 0
lib/private/Mail/Message.php

@@ -31,6 +31,7 @@ declare(strict_types=1);
  */
 namespace OC\Mail;
 
+use OCP\Mail\Headers\AutoSubmitted;
 use OCP\Mail\IAttachment;
 use OCP\Mail\IEMailTemplate;
 use OCP\Mail\IMessage;
@@ -301,4 +302,41 @@ class Message implements IMessage {
 		}
 		return $this;
 	}
+
+	/**
+	 * Add the Auto-Submitted header to the email, preventing most automated
+	 * responses to automated messages.
+	 *
+	 * @param AutoSubmitted::VALUE_* $value (one of AutoSubmitted::VALUE_NO, AutoSubmitted::VALUE_AUTO_GENERATED, AutoSubmitted::VALUE_AUTO_REPLIED)
+	 * @return $this
+	 */
+	public function setAutoSubmitted(string $value): IMessage {
+		$headers = $this->swiftMessage->getHeaders();
+
+		if ($headers->has(AutoSubmitted::HEADER)) {
+			// if the header already exsists, remove it.
+			// the value can be modified with some implementations
+			// of the interface \Swift_Mime_Header, however the
+			// interface doesn't, and this makes the static-code
+			// analysis unhappy.
+			$headers->remove(AutoSubmitted::HEADER);
+		}
+
+		$headers->addTextHeader(AutoSubmitted::HEADER, $value);
+
+		return $this;
+	}
+
+	/**
+	 * Get the current value of the Auto-Submitted header. Defaults to "no"
+	 * which is equivalent to the header not existing at all
+	 *
+	 * @return string
+	 */
+	public function getAutoSubmitted(): string {
+		$headers = $this->swiftMessage->getHeaders();
+
+		return $headers->has(AutoSubmitted::HEADER) ?
+			$headers->get(AutoSubmitted::HEADER)->toString() : AutoSubmitted::VALUE_NO;
+	}
 }

+ 75 - 0
lib/public/Mail/Headers/AutoSubmitted.php

@@ -0,0 +1,75 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2022 Bennet Becker <dev@bennet.cc>
+ *
+ * @author Bennet Becker <dev@bennet.cc>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+namespace OCP\Mail\Headers;
+
+/**
+ * Keyword values for the Auto-Submitted email header, as per RFC 3834.
+ *
+ * The value "auto-notified" as per RFC 5436 is deliberately omitted as it is
+ * meant of notification of the sieve system.
+ *
+ * @link https://www.iana.org/assignments/auto-submitted-keywords/auto-submitted-keywords.xhtml
+ *
+ * @since 26.0.0
+ */
+final class AutoSubmitted {
+
+	/**
+	 * Name of the Header as used in the final message later
+	 *
+	 * @var string
+	 * @since 26.0.0
+	 */
+	public const HEADER = 'Auto-Submitted';
+
+	/**
+	 * Indicates that a message was NOT automatically generated, but was
+	 * created by a human (or following human interaction). It is the equivalent
+	 * to the absence of an Auto-Submitted header altogether.
+	 *
+	 * @var string
+	 * @since 26.0.0
+	 */
+	public const VALUE_NO = 'no';
+
+	/**
+	 * Indicates that a message was generated by an automatic process, and is
+	 * not a direct response to another message
+	 *
+	 * @var string
+	 * @since 26.0.0
+	 */
+	public const VALUE_AUTO_GENERATED = 'auto-generated';
+
+	/**
+	 * Indicates that a message was automatically generated as a direct response
+	 * to another message.
+	 *
+	 * @var string
+	 * @since 26.0.0
+	 */
+	public const VALUE_AUTO_REPLIED = 'auto-replied';
+}

+ 10 - 0
lib/public/Mail/IMessage.php

@@ -93,4 +93,14 @@ interface IMessage {
 	 * @since 13.0.0
 	 */
 	public function useTemplate(IEMailTemplate $emailTemplate): IMessage;
+
+	/**
+	 * Add the Auto-Submitted header to the email, preventing most automated
+	 * responses to automated messages.
+	 *
+	 * @param Headers\AutoSubmitted::VALUE_* $value (one of AutoSubmitted::VALUE_NO, AutoSubmitted::VALUE_AUTO_GENERATED, AutoSubmitted::VALUE_AUTO_REPLIED)
+	 * @return IMessage
+	 * @since 26.0.0
+	 */
+	public function setAutoSubmitted(string $value): IMessage;
 }

+ 107 - 0
tests/lib/Mail/MessageTest.php

@@ -9,6 +9,7 @@
 namespace Test\Mail;
 
 use OC\Mail\Message;
+use OCP\Mail\Headers\AutoSubmitted;
 use OCP\Mail\IEMailTemplate;
 use Swift_Message;
 use Test\TestCase;
@@ -263,4 +264,110 @@ class MessageTest extends TestCase {
 
 		$message->useTemplate($template);
 	}
+
+	public function testSetAutoSubmitted1() {
+		$swiftMimeSimpleHeaderSet = $this->getMockBuilder('\Swift_Mime_SimpleHeaderSet')
+			->disableOriginalConstructor()
+			->getMock();
+		$swiftMessage = $this->getMockBuilder('\Swift_Message')
+			->disableOriginalConstructor()
+			->disableOriginalClone()
+			->disableArgumentCloning()
+			->disallowMockingUnknownTypes()
+			->getMock();
+
+		$swiftMessage->method('getHeaders')->willReturn($swiftMimeSimpleHeaderSet);
+
+		$swiftMimeSimpleHeaderSet->expects($this->once())
+			->method('has')
+			->with('Auto-Submitted');
+		$swiftMimeSimpleHeaderSet->expects($this->never())
+			->method('remove');
+		$swiftMimeSimpleHeaderSet->expects($this->once())
+			->method('addTextHeader')
+			->with('Auto-Submitted', AutoSubmitted::VALUE_AUTO_GENERATED);
+
+		$message = new Message($swiftMessage, false);
+		$message->setAutoSubmitted(AutoSubmitted::VALUE_AUTO_GENERATED);
+	}
+
+	public function testSetAutoSubmitted2() {
+		$swiftMimeSimpleHeaderSet = $this->getMockBuilder('\Swift_Mime_SimpleHeaderSet')
+			->disableOriginalConstructor()
+			->getMock();
+		$swiftMessage = $this->getMockBuilder('\Swift_Message')
+			->disableOriginalConstructor()
+			->disableOriginalClone()
+			->disableArgumentCloning()
+			->disallowMockingUnknownTypes()
+			->getMock();
+
+		$swiftMessage->method('getHeaders')->willReturn($swiftMimeSimpleHeaderSet);
+
+		$swiftMimeSimpleHeaderSet->expects($this->once())
+			->method('has')
+			->with('Auto-Submitted')
+			->willReturn(true);
+		$swiftMimeSimpleHeaderSet->expects($this->once())
+			->method('remove')
+			->with('Auto-Submitted');
+		$swiftMimeSimpleHeaderSet->expects($this->once())
+			->method('addTextHeader')
+			->with('Auto-Submitted', AutoSubmitted::VALUE_AUTO_GENERATED);
+
+		$message = new Message($swiftMessage, false);
+		$message->setAutoSubmitted(AutoSubmitted::VALUE_AUTO_GENERATED);
+	}
+
+	public function testGetAutoSubmitted1() {
+		$swiftMimeSimpleHeaderSet = $this->getMockBuilder('\Swift_Mime_SimpleHeaderSet')
+			->disableOriginalConstructor()
+			->getMock();
+		$swiftMessage = $this->getMockBuilder('\Swift_Message')
+			->disableOriginalConstructor()
+			->disableOriginalClone()
+			->disableArgumentCloning()
+			->disallowMockingUnknownTypes()
+			->getMock();
+
+		$swiftMessage->method('getHeaders')->willReturn($swiftMimeSimpleHeaderSet);
+
+		$swiftMimeSimpleHeaderSet->expects($this->once())
+			->method('has')
+			->with('Auto-Submitted');
+		$swiftMimeSimpleHeaderSet->expects($this->never())
+			->method('get');
+
+		$message = new Message($swiftMessage, false);
+		$this->assertSame("no", $message->getAutoSubmitted());
+	}
+	public function testGetAutoSubmitted2() {
+		$swiftMimeHeader = $this->getMockBuilder('\Swift_Mime_Header')
+			->disableOriginalConstructor()
+			->getMockForAbstractClass();
+		$swiftMimeSimpleHeaderSet = $this->getMockBuilder('\Swift_Mime_SimpleHeaderSet')
+			->disableOriginalConstructor()
+			->getMock();
+		$swiftMessage = $this->getMockBuilder('\Swift_Message')
+			->disableOriginalConstructor()
+			->disableOriginalClone()
+			->disableArgumentCloning()
+			->disallowMockingUnknownTypes()
+			->getMock();
+
+
+		$swiftMessage->method('getHeaders')->willReturn($swiftMimeSimpleHeaderSet);
+		$swiftMimeHeader->method('toString')->willReturn(AutoSubmitted::VALUE_AUTO_GENERATED);
+
+		$swiftMimeSimpleHeaderSet->expects($this->once())
+			->method('has')
+			->with('Auto-Submitted')
+			->willReturn(true);
+		$swiftMimeSimpleHeaderSet->expects($this->once())
+			->method('get')
+			->willReturn($swiftMimeHeader);
+
+		$message = new Message($swiftMessage, false);
+		$this->assertSame(AutoSubmitted::VALUE_AUTO_GENERATED, $message->getAutoSubmitted());
+	}
 }