Add support for the List-ID header to Email
authorTim Düsterhus <duesterhus@woltlab.com>
Mon, 29 Jun 2020 11:59:34 +0000 (13:59 +0200)
committerTim Düsterhus <duesterhus@woltlab.com>
Mon, 29 Jun 2020 14:12:27 +0000 (16:12 +0200)
see #3379

wcfsetup/install/files/lib/system/email/Email.class.php
wcfsetup/install/files/lib/system/email/EmailGrammar.class.php

index 7f60265fbcc3f35820d7fcddd0d9733b1d1a7f73..71ec1ac093b60f6511fc8c9b90d2e5c88d57825b 100644 (file)
@@ -57,6 +57,20 @@ class Email {
         */
        protected $inReplyTo = [];
        
+       /**
+        * List-Id header
+        * @var string
+        * @since 5.3
+        */
+       protected $listId = null;
+       
+       /**
+        * Human readable part of the List-Id header
+        * @var string
+        * @since 5.3
+        */
+       protected $listIdHuman = null;
+       
        /**
         * Date header
         * @var \DateTime
@@ -241,6 +255,52 @@ class Email {
                return $this->references;
        }
        
+       /**
+        * Sets the list-label part of the email's 'List-Id'.
+        * 
+        * @param       string          $listId
+        * @param       string          $humanReadable
+        * @throws      \DomainException
+        * @since 5.3
+        */
+       public function setListID($listId, $humanReadable = null) {
+               if ($listId === null) {
+                       $this->listId = null;
+                       return;
+               }
+               
+               if (!preg_match('(^'.EmailGrammar::getGrammar('list-label').'$)', $listId)) {
+                       throw new \DomainException("The given list id '".$listId."' is invalid.");
+               }
+               if (strlen($listId) > 200) {
+                       throw new \DomainException("The given list id '".$listId."' is not allowed. The maximum allowed length is 200 bytes.");
+               }
+               if ($humanReadable !== null) {
+                       $humanReadable = EmailGrammar::encodeHeader($humanReadable);
+                       if (!preg_match('(^'.EmailGrammar::getGrammar('phrase').'$)', $humanReadable)) {
+                               throw new \DomainException("The given human readable name '".$humanReadable."' is invalid.");
+                       }
+               }
+               
+               $this->listId = $listId;
+               $this->listIdHuman = $humanReadable;
+       }
+       
+       /**
+        * Returns the email's full 'List-Id' including the host. Returns 'null'
+        * if no 'List-Id' is set.
+        * 
+        * @return      ?string
+        * @since 5.3
+        */
+       public function getListID() {
+               if ($this->listId === null) {
+                       return null;
+               }
+               
+               return ($this->listIdHuman ? $this->listIdHuman.' ' : '').'<'.$this->listId.'.list-id.'.self::getHost().'>';
+       }
+       
        /**
         * Sets the email's 'From'.
         * 
@@ -394,6 +454,9 @@ class Email {
                if ($this->getInReplyTo()) {
                        $headers[] = ['in-reply-to', implode("\r\n   ", $this->getInReplyTo())];
                }
+               if ($this->getListID()) {
+                       $headers[] = ['list-id', $this->getListID()];
+               }
                $headers[] = ['mime-version', '1.0'];
                
                if (!$this->body) {
@@ -425,6 +488,9 @@ class Email {
                                case 'message-id':
                                        $name = 'Message-ID';
                                        break;
+                               case 'list-id':
+                                       $name = 'List-ID';
+                                       break;
                                case 'mime-version':
                                        $name = 'MIME-Version';
                                        break;
index 504060ebdd214010b2430a1a52a66e107414481f..60229c05c390e9517bf35f65d5541578ea6463bc 100644 (file)
@@ -36,6 +36,7 @@ final class EmailGrammar {
                        case 'atom':
                                return "(?:".self::getGrammar('CFWS')."?".self::getGrammar('atext')."+".self::getGrammar('CFWS')."?)";
                        case 'id-left':
+                       case 'list-label':
                        case 'dot-atom-text':
                                return "(?:".self::getGrammar('atext')."+(?:\\.".self::getGrammar('atext').'+)*)';
                        case 'no-fold-literal':