git subrepo commit (merge) mailcow/src/mailcow-dockerized

subrepo: subdir:   "mailcow/src/mailcow-dockerized"
  merged:   "02ae5285"
upstream: origin:   "https://github.com/mailcow/mailcow-dockerized.git"
  branch:   "master"
  commit:   "649a5c01"
git-subrepo: version:  "0.4.3"
  origin:   "???"
  commit:   "???"
Change-Id: I870ad468fba026cc5abf3c5699ed1e12ff28b32b
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/phpmailer/phpmailer/src/PHPMailer.php b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/phpmailer/phpmailer/src/PHPMailer.php
index c8fc1a8..eb4b742 100644
--- a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/phpmailer/phpmailer/src/PHPMailer.php
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/phpmailer/phpmailer/src/PHPMailer.php
@@ -428,9 +428,11 @@
     public $Debugoutput = 'echo';
 
     /**
-     * Whether to keep SMTP connection open after each message.
-     * If this is set to true then to close the connection
-     * requires an explicit call to smtpClose().
+     * Whether to keep the SMTP connection open after each message.
+     * If this is set to true then the connection will remain open after a send,
+     * and closing the connection will require an explicit call to smtpClose().
+     * It's a good idea to use this if you are sending multiple messages as it reduces overhead.
+     * See the mailing list example for how to use it.
      *
      * @var bool
      */
@@ -748,7 +750,7 @@
      *
      * @var string
      */
-    const VERSION = '6.2.0';
+    const VERSION = '6.5.0';
 
     /**
      * Error severity: message only, continue processing.
@@ -862,18 +864,25 @@
             $subject = $this->encodeHeader($this->secureHeader($subject));
         }
         //Calling mail() with null params breaks
+        $this->edebug('Sending with mail()');
+        $this->edebug('Sendmail path: ' . ini_get('sendmail_path'));
+        $this->edebug("Envelope sender: {$this->Sender}");
+        $this->edebug("To: {$to}");
+        $this->edebug("Subject: {$subject}");
+        $this->edebug("Headers: {$header}");
         if (!$this->UseSendmailOptions || null === $params) {
             $result = @mail($to, $subject, $body, $header);
         } else {
+            $this->edebug("Additional params: {$params}");
             $result = @mail($to, $subject, $body, $header, $params);
         }
-
+        $this->edebug('Result: ' . ($result ? 'true' : 'false'));
         return $result;
     }
 
     /**
-     * Output debugging info via user-defined method.
-     * Only generates output if SMTP debug output is enabled (@see SMTP::$do_debug).
+     * Output debugging info via a user-defined method.
+     * Only generates output if debug output is enabled.
      *
      * @see PHPMailer::$Debugoutput
      * @see PHPMailer::$SMTPDebug
@@ -1070,7 +1079,7 @@
         $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
         $pos = strrpos($address, '@');
         if (false === $pos) {
-            // At-sign is missing.
+            //At-sign is missing.
             $error_message = sprintf(
                 '%s (%s): %s',
                 $this->lang('invalid_address'),
@@ -1086,7 +1095,7 @@
             return false;
         }
         $params = [$kind, $address, $name];
-        // Enqueue addresses with IDN until we know the PHPMailer::$CharSet.
+        //Enqueue addresses with IDN until we know the PHPMailer::$CharSet.
         if (static::idnSupported() && $this->has8bitChars(substr($address, ++$pos))) {
             if ('Reply-To' !== $kind) {
                 if (!array_key_exists($address, $this->RecipientsQueue)) {
@@ -1103,7 +1112,7 @@
             return false;
         }
 
-        // Immediately add standard addresses without IDN.
+        //Immediately add standard addresses without IDN.
         return call_user_func_array([$this, 'addAnAddress'], $params);
     }
 
@@ -1191,6 +1200,15 @@
                         $address->mailbox . '@' . $address->host
                     )
                 ) {
+                    //Decode the name part if it's present and encoded
+                    if (
+                        property_exists($address, 'personal') &&
+                        extension_loaded('mbstring') &&
+                        preg_match('/^=\?.*\?=$/', $address->personal)
+                    ) {
+                        $address->personal = mb_decode_mimeheader($address->personal);
+                    }
+
                     $addresses[] = [
                         'name' => (property_exists($address, 'personal') ? $address->personal : ''),
                         'address' => $address->mailbox . '@' . $address->host,
@@ -1214,9 +1232,15 @@
                 } else {
                     list($name, $email) = explode('<', $address);
                     $email = trim(str_replace('>', '', $email));
+                    $name = trim($name);
                     if (static::validateAddress($email)) {
+                        //If this name is encoded, decode it
+                        if (preg_match('/^=\?.*\?=$/', $name)) {
+                            $name = mb_decode_mimeheader($name);
+                        }
                         $addresses[] = [
-                            'name' => trim(str_replace(['"', "'"], '', $name)),
+                            //Remove any surrounding quotes and spaces from the name
+                            'name' => trim($name, '\'" '),
                             'address' => $email,
                         ];
                     }
@@ -1242,7 +1266,7 @@
     {
         $address = trim($address);
         $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
-        // Don't validate now addresses with IDN. Will be done in send().
+        //Don't validate now addresses with IDN. Will be done in send().
         $pos = strrpos($address, '@');
         if (
             (false === $pos)
@@ -1313,7 +1337,8 @@
         if (null === $patternselect) {
             $patternselect = static::$validator;
         }
-        if (is_callable($patternselect)) {
+        //Don't allow strings as callables, see SECURITY.md and CVE-2021-3603
+        if (is_callable($patternselect) && !is_string($patternselect)) {
             return call_user_func($patternselect, $address);
         }
         //Reject line breaks in addresses; it's valid RFC5322, but not RFC5321
@@ -1395,7 +1420,7 @@
      */
     public function punyencodeAddress($address)
     {
-        // Verify we have required functions, CharSet, and at-sign.
+        //Verify we have required functions, CharSet, and at-sign.
         $pos = strrpos($address, '@');
         if (
             !empty($this->CharSet) &&
@@ -1403,16 +1428,20 @@
             static::idnSupported()
         ) {
             $domain = substr($address, ++$pos);
-            // Verify CharSet string is a valid one, and domain properly encoded in this CharSet.
+            //Verify CharSet string is a valid one, and domain properly encoded in this CharSet.
             if ($this->has8bitChars($domain) && @mb_check_encoding($domain, $this->CharSet)) {
-                $domain = mb_convert_encoding($domain, 'UTF-8', $this->CharSet);
+                //Convert the domain from whatever charset it's in to UTF-8
+                $domain = mb_convert_encoding($domain, self::CHARSET_UTF8, $this->CharSet);
                 //Ignore IDE complaints about this line - method signature changed in PHP 5.4
                 $errorcode = 0;
                 if (defined('INTL_IDNA_VARIANT_UTS46')) {
-                    $punycode = idn_to_ascii($domain, $errorcode, INTL_IDNA_VARIANT_UTS46);
+                    //Use the current punycode standard (appeared in PHP 7.2)
+                    $punycode = idn_to_ascii($domain, $errorcode, \INTL_IDNA_VARIANT_UTS46);
                 } elseif (defined('INTL_IDNA_VARIANT_2003')) {
-                    $punycode = idn_to_ascii($domain, $errorcode, INTL_IDNA_VARIANT_2003);
+                    //Fall back to this old, deprecated/removed encoding
+                    $punycode = idn_to_ascii($domain, $errorcode, \INTL_IDNA_VARIANT_2003);
                 } else {
+                    //Fall back to a default we don't know about
                     $punycode = idn_to_ascii($domain, $errorcode);
                 }
                 if (false !== $punycode) {
@@ -1462,7 +1491,7 @@
     {
         if (
             'smtp' === $this->Mailer
-            || ('mail' === $this->Mailer && (PHP_VERSION_ID >= 80000 || stripos(PHP_OS, 'WIN') === 0))
+            || ('mail' === $this->Mailer && (\PHP_VERSION_ID >= 80000 || stripos(PHP_OS, 'WIN') === 0))
         ) {
             //SMTP mandates RFC-compliant line endings
             //and it's also used with mail() on Windows
@@ -1474,8 +1503,8 @@
         //Check for buggy PHP versions that add a header with an incorrect line break
         if (
             'mail' === $this->Mailer
-            && ((PHP_VERSION_ID >= 70000 && PHP_VERSION_ID < 70017)
-                || (PHP_VERSION_ID >= 70100 && PHP_VERSION_ID < 70103))
+            && ((\PHP_VERSION_ID >= 70000 && \PHP_VERSION_ID < 70017)
+                || (\PHP_VERSION_ID >= 70100 && \PHP_VERSION_ID < 70103))
             && ini_get('mail.add_x_header') === '1'
             && stripos(PHP_OS, 'WIN') === 0
         ) {
@@ -1488,10 +1517,10 @@
         }
 
         try {
-            $this->error_count = 0; // Reset errors
+            $this->error_count = 0; //Reset errors
             $this->mailHeader = '';
 
-            // Dequeue recipient and Reply-To addresses with IDN
+            //Dequeue recipient and Reply-To addresses with IDN
             foreach (array_merge($this->RecipientsQueue, $this->ReplyToQueue) as $params) {
                 $params[1] = $this->punyencodeAddress($params[1]);
                 call_user_func_array([$this, 'addAnAddress'], $params);
@@ -1500,7 +1529,7 @@
                 throw new Exception($this->lang('provide_address'), self::STOP_CRITICAL);
             }
 
-            // Validate From, Sender, and ConfirmReadingTo addresses
+            //Validate From, Sender, and ConfirmReadingTo addresses
             foreach (['From', 'Sender', 'ConfirmReadingTo'] as $address_kind) {
                 $this->$address_kind = trim($this->$address_kind);
                 if (empty($this->$address_kind)) {
@@ -1524,29 +1553,29 @@
                 }
             }
 
-            // Set whether the message is multipart/alternative
+            //Set whether the message is multipart/alternative
             if ($this->alternativeExists()) {
                 $this->ContentType = static::CONTENT_TYPE_MULTIPART_ALTERNATIVE;
             }
 
             $this->setMessageType();
-            // Refuse to send an empty message unless we are specifically allowing it
+            //Refuse to send an empty message unless we are specifically allowing it
             if (!$this->AllowEmpty && empty($this->Body)) {
                 throw new Exception($this->lang('empty_message'), self::STOP_CRITICAL);
             }
 
             //Trim subject consistently
             $this->Subject = trim($this->Subject);
-            // Create body before headers in case body makes changes to headers (e.g. altering transfer encoding)
+            //Create body before headers in case body makes changes to headers (e.g. altering transfer encoding)
             $this->MIMEHeader = '';
             $this->MIMEBody = $this->createBody();
-            // createBody may have added some headers, so retain them
+            //createBody may have added some headers, so retain them
             $tempheaders = $this->MIMEHeader;
             $this->MIMEHeader = $this->createHeader();
             $this->MIMEHeader .= $tempheaders;
 
-            // To capture the complete message when using mail(), create
-            // an extra header list which createHeader() doesn't fold in
+            //To capture the complete message when using mail(), create
+            //an extra header list which createHeader() doesn't fold in
             if ('mail' === $this->Mailer) {
                 if (count($this->to) > 0) {
                     $this->mailHeader .= $this->addrAppend('To', $this->to);
@@ -1559,7 +1588,7 @@
                 );
             }
 
-            // Sign with DKIM if enabled
+            //Sign with DKIM if enabled
             if (
                 !empty($this->DKIM_domain)
                 && !empty($this->DKIM_selector)
@@ -1600,7 +1629,7 @@
     public function postSend()
     {
         try {
-            // Choose the mailer and send through it
+            //Choose the mailer and send through it
             switch ($this->Mailer) {
                 case 'sendmail':
                 case 'qmail':
@@ -1645,22 +1674,44 @@
      */
     protected function sendmailSend($header, $body)
     {
+        if ($this->Mailer === 'qmail') {
+            $this->edebug('Sending with qmail');
+        } else {
+            $this->edebug('Sending with sendmail');
+        }
         $header = static::stripTrailingWSP($header) . static::$LE . static::$LE;
-
-        // CVE-2016-10033, CVE-2016-10045: Don't pass -f if characters will be escaped.
-        if (!empty($this->Sender) && self::isShellSafe($this->Sender)) {
-            if ('qmail' === $this->Mailer) {
+        //This sets the SMTP envelope sender which gets turned into a return-path header by the receiver
+        //A space after `-f` is optional, but there is a long history of its presence
+        //causing problems, so we don't use one
+        //Exim docs: http://www.exim.org/exim-html-current/doc/html/spec_html/ch-the_exim_command_line.html
+        //Sendmail docs: http://www.sendmail.org/~ca/email/man/sendmail.html
+        //Qmail docs: http://www.qmail.org/man/man8/qmail-inject.html
+        //Example problem: https://www.drupal.org/node/1057954
+        if (empty($this->Sender) && !empty(ini_get('sendmail_from'))) {
+            //PHP config has a sender address we can use
+            $this->Sender = ini_get('sendmail_from');
+        }
+        //CVE-2016-10033, CVE-2016-10045: Don't pass -f if characters will be escaped.
+        if (!empty($this->Sender) && static::validateAddress($this->Sender) && self::isShellSafe($this->Sender)) {
+            if ($this->Mailer === 'qmail') {
                 $sendmailFmt = '%s -f%s';
             } else {
                 $sendmailFmt = '%s -oi -f%s -t';
             }
-        } elseif ('qmail' === $this->Mailer) {
-            $sendmailFmt = '%s';
         } else {
+            //allow sendmail to choose a default envelope sender. It may
+            //seem preferable to force it to use the From header as with
+            //SMTP, but that introduces new problems (see
+            //<https://github.com/PHPMailer/PHPMailer/issues/2298>), and
+            //it has historically worked this way.
             $sendmailFmt = '%s -oi -t';
         }
 
         $sendmail = sprintf($sendmailFmt, escapeshellcmd($this->Sendmail), $this->Sender);
+        $this->edebug('Sendmail path: ' . $this->Sendmail);
+        $this->edebug('Sendmail command: ' . $sendmail);
+        $this->edebug('Envelope sender: ' . $this->Sender);
+        $this->edebug("Headers: {$header}");
 
         if ($this->SingleTo) {
             foreach ($this->SingleToArray as $toAddr) {
@@ -1668,13 +1719,15 @@
                 if (!$mail) {
                     throw new Exception($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
                 }
+                $this->edebug("To: {$toAddr}");
                 fwrite($mail, 'To: ' . $toAddr . "\n");
                 fwrite($mail, $header);
                 fwrite($mail, $body);
                 $result = pclose($mail);
+                $addrinfo = static::parseAddresses($toAddr);
                 $this->doCallback(
                     ($result === 0),
-                    [$toAddr],
+                    [[$addrinfo['address'], $addrinfo['name']]],
                     $this->cc,
                     $this->bcc,
                     $this->Subject,
@@ -1682,6 +1735,7 @@
                     $this->From,
                     []
                 );
+                $this->edebug("Result: " . ($result === 0 ? 'true' : 'false'));
                 if (0 !== $result) {
                     throw new Exception($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
                 }
@@ -1704,6 +1758,7 @@
                 $this->From,
                 []
             );
+            $this->edebug("Result: " . ($result === 0 ? 'true' : 'false'));
             if (0 !== $result) {
                 throw new Exception($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
             }
@@ -1724,7 +1779,7 @@
      */
     protected static function isShellSafe($string)
     {
-        // Future-proof
+        //Future-proof
         if (
             escapeshellcmd($string) !== $string
             || !in_array(escapeshellarg($string), ["'$string'", "\"$string\""])
@@ -1737,9 +1792,9 @@
         for ($i = 0; $i < $length; ++$i) {
             $c = $string[$i];
 
-            // All other characters have a special meaning in at least one common shell, including = and +.
-            // Full stop (.) has a special meaning in cmd.exe, but its impact should be negligible here.
-            // Note that this does permit non-Latin alphanumeric characters based on the current locale.
+            //All other characters have a special meaning in at least one common shell, including = and +.
+            //Full stop (.) has a special meaning in cmd.exe, but its impact should be negligible here.
+            //Note that this does permit non-Latin alphanumeric characters based on the current locale.
             if (!ctype_alnum($c) && strpos('@_-.', $c) === false) {
                 return false;
             }
@@ -1759,7 +1814,8 @@
      */
     protected static function isPermittedPath($path)
     {
-        return !preg_match('#^[a-z]+://#i', $path);
+        //Matches scheme definition from https://tools.ietf.org/html/rfc3986#section-3.1
+        return !preg_match('#^[a-z][a-z\d+.-]*://#i', $path);
     }
 
     /**
@@ -1771,12 +1827,15 @@
      */
     protected static function fileIsAccessible($path)
     {
+        if (!static::isPermittedPath($path)) {
+            return false;
+        }
         $readable = file_exists($path);
         //If not a UNC path (expected to start with \\), check read permission, see #2069
         if (strpos($path, '\\\\') !== 0) {
             $readable = $readable && is_readable($path);
         }
-        return static::isPermittedPath($path) && $readable;
+        return  $readable;
     }
 
     /**
@@ -1809,11 +1868,15 @@
         //Sendmail docs: http://www.sendmail.org/~ca/email/man/sendmail.html
         //Qmail docs: http://www.qmail.org/man/man8/qmail-inject.html
         //Example problem: https://www.drupal.org/node/1057954
-        // CVE-2016-10033, CVE-2016-10045: Don't pass -f if characters will be escaped.
-        if (!empty($this->Sender) && static::validateAddress($this->Sender) && self::isShellSafe($this->Sender)) {
-            $params = sprintf('-f%s', $this->Sender);
+        //CVE-2016-10033, CVE-2016-10045: Don't pass -f if characters will be escaped.
+        if (empty($this->Sender) && !empty(ini_get('sendmail_from'))) {
+            //PHP config has a sender address we can use
+            $this->Sender = ini_get('sendmail_from');
         }
         if (!empty($this->Sender) && static::validateAddress($this->Sender)) {
+            if (self::isShellSafe($this->Sender)) {
+                $params = sprintf('-f%s', $this->Sender);
+            }
             $old_from = ini_get('sendmail_from');
             ini_set('sendmail_from', $this->Sender);
         }
@@ -1821,7 +1884,17 @@
         if ($this->SingleTo && count($toArr) > 1) {
             foreach ($toArr as $toAddr) {
                 $result = $this->mailPassthru($toAddr, $this->Subject, $body, $header, $params);
-                $this->doCallback($result, [$toAddr], $this->cc, $this->bcc, $this->Subject, $body, $this->From, []);
+                $addrinfo = static::parseAddresses($toAddr);
+                $this->doCallback(
+                    $result,
+                    [[$addrinfo['address'], $addrinfo['name']]],
+                    $this->cc,
+                    $this->bcc,
+                    $this->Subject,
+                    $body,
+                    $this->From,
+                    []
+                );
             }
         } else {
             $result = $this->mailPassthru($to, $this->Subject, $body, $header, $params);
@@ -1899,7 +1972,7 @@
         }
 
         $callbacks = [];
-        // Attempt to send to all recipients
+        //Attempt to send to all recipients
         foreach ([$this->to, $this->cc, $this->bcc] as $togroup) {
             foreach ($togroup as $to) {
                 if (!$this->smtp->recipient($to[0], $this->dsn)) {
@@ -1910,11 +1983,11 @@
                     $isSent = true;
                 }
 
-                $callbacks[] = ['issent' => $isSent, 'to' => $to[0]];
+                $callbacks[] = ['issent' => $isSent, 'to' => $to[0], 'name' => $to[1]];
             }
         }
 
-        // Only send the DATA command if we have viable recipients
+        //Only send the DATA command if we have viable recipients
         if ((count($this->all_recipients) > count($bad_rcpt)) && !$this->smtp->data($header . $body)) {
             throw new Exception($this->lang('data_not_accepted'), self::STOP_CRITICAL);
         }
@@ -1931,7 +2004,7 @@
         foreach ($callbacks as $cb) {
             $this->doCallback(
                 $cb['issent'],
-                [$cb['to']],
+                [[$cb['to'], $cb['name']]],
                 [],
                 [],
                 $this->Subject,
@@ -1976,7 +2049,7 @@
             $options = $this->SMTPOptions;
         }
 
-        // Already connected?
+        //Already connected?
         if ($this->smtp->connected()) {
             return true;
         }
@@ -1998,14 +2071,14 @@
                 )
             ) {
                 $this->edebug($this->lang('invalid_hostentry') . ' ' . trim($hostentry));
-                // Not a valid host entry
+                //Not a valid host entry
                 continue;
             }
-            // $hostinfo[1]: optional ssl or tls prefix
-            // $hostinfo[2]: the hostname
-            // $hostinfo[3]: optional port number
-            // The host string prefix can temporarily override the current setting for SMTPSecure
-            // If it's not specified, the default value is used
+            //$hostinfo[1]: optional ssl or tls prefix
+            //$hostinfo[2]: the hostname
+            //$hostinfo[3]: optional port number
+            //The host string prefix can temporarily override the current setting for SMTPSecure
+            //If it's not specified, the default value is used
 
             //Check the host name is a valid name or IP address before trying to use it
             if (!static::isValidHost($hostinfo[2])) {
@@ -2017,11 +2090,11 @@
             $tls = (static::ENCRYPTION_STARTTLS === $this->SMTPSecure);
             if ('ssl' === $hostinfo[1] || ('' === $hostinfo[1] && static::ENCRYPTION_SMTPS === $this->SMTPSecure)) {
                 $prefix = 'ssl://';
-                $tls = false; // Can't have SSL and TLS at the same time
+                $tls = false; //Can't have SSL and TLS at the same time
                 $secure = static::ENCRYPTION_SMTPS;
             } elseif ('tls' === $hostinfo[1]) {
                 $tls = true;
-                // tls doesn't use a prefix
+                //TLS doesn't use a prefix
                 $secure = static::ENCRYPTION_STARTTLS;
             }
             //Do we need the OpenSSL extension?
@@ -2051,10 +2124,10 @@
                     }
                     $this->smtp->hello($hello);
                     //Automatically enable TLS encryption if:
-                    // * it's not disabled
-                    // * we have openssl extension
-                    // * we are not already using SSL
-                    // * the server offers STARTTLS
+                    //* it's not disabled
+                    //* we have openssl extension
+                    //* we are not already using SSL
+                    //* the server offers STARTTLS
                     if ($this->SMTPAutoTLS && $sslext && 'ssl' !== $secure && $this->smtp->getServerExt('STARTTLS')) {
                         $tls = true;
                     }
@@ -2062,7 +2135,7 @@
                         if (!$this->smtp->startTLS()) {
                             throw new Exception($this->lang('connect_host'));
                         }
-                        // We must resend EHLO after TLS negotiation
+                        //We must resend EHLO after TLS negotiation
                         $this->smtp->hello($hello);
                     }
                     if (
@@ -2080,14 +2153,14 @@
                 } catch (Exception $exc) {
                     $lastexception = $exc;
                     $this->edebug($exc->getMessage());
-                    // We must have connected, but then failed TLS or Auth, so close connection nicely
+                    //We must have connected, but then failed TLS or Auth, so close connection nicely
                     $this->smtp->quit();
                 }
             }
         }
-        // If we get here, all connection attempts have failed, so close connection hard
+        //If we get here, all connection attempts have failed, so close connection hard
         $this->smtp->close();
-        // As we've caught all exceptions, just report whatever the last one was
+        //As we've caught all exceptions, just report whatever the last one was
         if ($this->exceptions && null !== $lastexception) {
             throw $lastexception;
         }
@@ -2112,13 +2185,14 @@
      * The default language is English.
      *
      * @param string $langcode  ISO 639-1 2-character language code (e.g. French is "fr")
-     * @param string $lang_path Path to the language file directory, with trailing separator (slash)
+     * @param string $lang_path Path to the language file directory, with trailing separator (slash).D
+     *                          Do not set this from user input!
      *
      * @return bool
      */
     public function setLanguage($langcode = 'en', $lang_path = '')
     {
-        // Backwards compatibility for renamed language codes
+        //Backwards compatibility for renamed language codes
         $renamed_langcodes = [
             'br' => 'pt_br',
             'cz' => 'cs',
@@ -2134,7 +2208,7 @@
             $langcode = $renamed_langcodes[$langcode];
         }
 
-        // Define full set of translatable strings in English
+        //Define full set of translatable strings in English
         $PHPMAILER_LANG = [
             'authenticate' => 'SMTP Error: Could not authenticate.',
             'connect_host' => 'SMTP Error: Could not connect to SMTP host.',
@@ -2159,7 +2233,7 @@
             'extension_missing' => 'Extension missing: ',
         ];
         if (empty($lang_path)) {
-            // Calculate an absolute path so it can work if CWD is not here
+            //Calculate an absolute path so it can work if CWD is not here
             $lang_path = dirname(__DIR__) . DIRECTORY_SEPARATOR . 'language' . DIRECTORY_SEPARATOR;
         }
         //Validate $langcode
@@ -2168,20 +2242,38 @@
         }
         $foundlang = true;
         $lang_file = $lang_path . 'phpmailer.lang-' . $langcode . '.php';
-        // There is no English translation file
+        //There is no English translation file
         if ('en' !== $langcode) {
-            // Make sure language file path is readable
+            //Make sure language file path is readable
             if (!static::fileIsAccessible($lang_file)) {
                 $foundlang = false;
             } else {
-                // Overwrite language-specific strings.
-                // This way we'll never have missing translation keys.
-                $foundlang = include $lang_file;
+                //$foundlang = include $lang_file;
+                $lines = file($lang_file);
+                foreach ($lines as $line) {
+                    //Translation file lines look like this:
+                    //$PHPMAILER_LANG['authenticate'] = 'SMTP-Fehler: Authentifizierung fehlgeschlagen.';
+                    //These files are parsed as text and not PHP so as to avoid the possibility of code injection
+                    //See https://blog.stevenlevithan.com/archives/match-quoted-string
+                    $matches = [];
+                    if (
+                        preg_match(
+                            '/^\$PHPMAILER_LANG\[\'([a-z\d_]+)\'\]\s*=\s*(["\'])(.+)*?\2;/',
+                            $line,
+                            $matches
+                        ) &&
+                        //Ignore unknown translation keys
+                        array_key_exists($matches[1], $PHPMAILER_LANG)
+                    ) {
+                        //Overwrite language-specific strings so we'll never have missing translation keys.
+                        $PHPMAILER_LANG[$matches[1]] = (string)$matches[3];
+                    }
+                }
             }
         }
         $this->language = $PHPMAILER_LANG;
 
-        return (bool) $foundlang; // Returns false if language not found
+        return $foundlang; //Returns false if language not found
     }
 
     /**
@@ -2225,7 +2317,7 @@
      */
     public function addrFormat($addr)
     {
-        if (empty($addr[1])) { // No name provided
+        if (empty($addr[1])) { //No name provided
             return $this->secureHeader($addr[0]);
         }
 
@@ -2252,8 +2344,8 @@
         } else {
             $soft_break = static::$LE;
         }
-        // If utf-8 encoding is used, we will need to make sure we don't
-        // split multibyte characters when we wrap
+        //If utf-8 encoding is used, we will need to make sure we don't
+        //split multibyte characters when we wrap
         $is_utf8 = static::CHARSET_UTF8 === strtolower($this->CharSet);
         $lelen = strlen(static::$LE);
         $crlflen = strlen(static::$LE);
@@ -2353,29 +2445,29 @@
             $lastChunk = substr($encodedText, $maxLength - $lookBack, $lookBack);
             $encodedCharPos = strpos($lastChunk, '=');
             if (false !== $encodedCharPos) {
-                // Found start of encoded character byte within $lookBack block.
-                // Check the encoded byte value (the 2 chars after the '=')
+                //Found start of encoded character byte within $lookBack block.
+                //Check the encoded byte value (the 2 chars after the '=')
                 $hex = substr($encodedText, $maxLength - $lookBack + $encodedCharPos + 1, 2);
                 $dec = hexdec($hex);
                 if ($dec < 128) {
-                    // Single byte character.
-                    // If the encoded char was found at pos 0, it will fit
-                    // otherwise reduce maxLength to start of the encoded char
+                    //Single byte character.
+                    //If the encoded char was found at pos 0, it will fit
+                    //otherwise reduce maxLength to start of the encoded char
                     if ($encodedCharPos > 0) {
                         $maxLength -= $lookBack - $encodedCharPos;
                     }
                     $foundSplitPos = true;
                 } elseif ($dec >= 192) {
-                    // First byte of a multi byte character
-                    // Reduce maxLength to split at start of character
+                    //First byte of a multi byte character
+                    //Reduce maxLength to split at start of character
                     $maxLength -= $lookBack - $encodedCharPos;
                     $foundSplitPos = true;
                 } elseif ($dec < 192) {
-                    // Middle byte of a multi byte character, look further back
+                    //Middle byte of a multi byte character, look further back
                     $lookBack += 3;
                 }
             } else {
-                // No encoded character found
+                //No encoded character found
                 $foundSplitPos = true;
             }
         }
@@ -2419,7 +2511,7 @@
 
         $result .= $this->headerLine('Date', '' === $this->MessageDate ? self::rfcDate() : $this->MessageDate);
 
-        // The To header is created automatically by mail(), so needs to be omitted here
+        //The To header is created automatically by mail(), so needs to be omitted here
         if ('mail' !== $this->Mailer) {
             if ($this->SingleTo) {
                 foreach ($this->to as $toaddr) {
@@ -2433,12 +2525,12 @@
         }
         $result .= $this->addrAppend('From', [[trim($this->From), $this->FromName]]);
 
-        // sendmail and mail() extract Cc from the header before sending
+        //sendmail and mail() extract Cc from the header before sending
         if (count($this->cc) > 0) {
             $result .= $this->addrAppend('Cc', $this->cc);
         }
 
-        // sendmail and mail() extract Bcc from the header before sending
+        //sendmail and mail() extract Bcc from the header before sending
         if (
             (
                 'sendmail' === $this->Mailer || 'qmail' === $this->Mailer || 'mail' === $this->Mailer
@@ -2452,13 +2544,13 @@
             $result .= $this->addrAppend('Reply-To', $this->ReplyTo);
         }
 
-        // mail() sets the subject itself
+        //mail() sets the subject itself
         if ('mail' !== $this->Mailer) {
             $result .= $this->headerLine('Subject', $this->encodeHeader($this->secureHeader($this->Subject)));
         }
 
-        // Only allow a custom message ID if it conforms to RFC 5322 section 3.6.4
-        // https://tools.ietf.org/html/rfc5322#section-3.6.4
+        //Only allow a custom message ID if it conforms to RFC 5322 section 3.6.4
+        //https://tools.ietf.org/html/rfc5322#section-3.6.4
         if ('' !== $this->MessageID && preg_match('/^<.*@.*>$/', $this->MessageID)) {
             $this->lastMessageID = $this->MessageID;
         } else {
@@ -2484,7 +2576,7 @@
             $result .= $this->headerLine('Disposition-Notification-To', '<' . $this->ConfirmReadingTo . '>');
         }
 
-        // Add custom headers
+        //Add custom headers
         foreach ($this->CustomHeader as $header) {
             $result .= $this->headerLine(
                 trim($header[0]),
@@ -2526,28 +2618,24 @@
                 $result .= $this->textLine(' boundary="' . $this->boundary[1] . '"');
                 break;
             default:
-                // Catches case 'plain': and case '':
+                //Catches case 'plain': and case '':
                 $result .= $this->textLine('Content-Type: ' . $this->ContentType . '; charset=' . $this->CharSet);
                 $ismultipart = false;
                 break;
         }
-        // RFC1341 part 5 says 7bit is assumed if not specified
+        //RFC1341 part 5 says 7bit is assumed if not specified
         if (static::ENCODING_7BIT !== $this->Encoding) {
-            // RFC 2045 section 6.4 says multipart MIME parts may only use 7bit, 8bit or binary CTE
+            //RFC 2045 section 6.4 says multipart MIME parts may only use 7bit, 8bit or binary CTE
             if ($ismultipart) {
                 if (static::ENCODING_8BIT === $this->Encoding) {
                     $result .= $this->headerLine('Content-Transfer-Encoding', static::ENCODING_8BIT);
                 }
-                // The only remaining alternatives are quoted-printable and base64, which are both 7bit compatible
+                //The only remaining alternatives are quoted-printable and base64, which are both 7bit compatible
             } else {
                 $result .= $this->headerLine('Content-Transfer-Encoding', $this->Encoding);
             }
         }
 
-        if ('mail' !== $this->Mailer) {
-//            $result .= static::$LE;
-        }
-
         return $result;
     }
 
@@ -2816,7 +2904,7 @@
                 $body .= $this->attachAll('attachment', $this->boundary[1]);
                 break;
             default:
-                // Catch case 'plain' and case '', applies to simple `text/plain` and `text/html` body content types
+                //Catch case 'plain' and case '', applies to simple `text/plain` and `text/html` body content types
                 //Reset the `Encoding` property in case we changed it for line length reasons
                 $this->Encoding = $bodyEncoding;
                 $body .= $this->encodeString($this->Body, $this->Encoding);
@@ -2907,7 +2995,7 @@
         $result .= $this->textLine('--' . $boundary);
         $result .= sprintf('Content-Type: %s; charset=%s', $contentType, $charSet);
         $result .= static::$LE;
-        // RFC1341 part 5 says 7bit is assumed if not specified
+        //RFC1341 part 5 says 7bit is assumed if not specified
         if (static::ENCODING_7BIT !== $encoding) {
             $result .= $this->headerLine('Content-Transfer-Encoding', $encoding);
         }
@@ -3005,7 +3093,7 @@
                 throw new Exception($this->lang('file_access') . $path, self::STOP_CONTINUE);
             }
 
-            // If a MIME type is not specified, try to work it out from the file name
+            //If a MIME type is not specified, try to work it out from the file name
             if ('' === $type) {
                 $type = static::filenameToType($path);
             }
@@ -3024,7 +3112,7 @@
                 2 => $name,
                 3 => $encoding,
                 4 => $type,
-                5 => false, // isStringAttachment
+                5 => false, //isStringAttachment
                 6 => $disposition,
                 7 => $name,
             ];
@@ -3064,16 +3152,16 @@
      */
     protected function attachAll($disposition_type, $boundary)
     {
-        // Return text of body
+        //Return text of body
         $mime = [];
         $cidUniq = [];
         $incl = [];
 
-        // Add all attachments
+        //Add all attachments
         foreach ($this->attachment as $attachment) {
-            // Check if it is a valid disposition_filter
+            //Check if it is a valid disposition_filter
             if ($attachment[6] === $disposition_type) {
-                // Check for string attachment
+                //Check for string attachment
                 $string = '';
                 $path = '';
                 $bString = $attachment[5];
@@ -3114,7 +3202,7 @@
                         static::$LE
                     );
                 }
-                // RFC1341 part 5 says 7bit is assumed if not specified
+                //RFC1341 part 5 says 7bit is assumed if not specified
                 if (static::ENCODING_7BIT !== $encoding) {
                     $mime[] = sprintf('Content-Transfer-Encoding: %s%s', $encoding, static::$LE);
                 }
@@ -3124,7 +3212,7 @@
                     $mime[] = 'Content-ID: <' . $this->encodeHeader($this->secureHeader($cid)) . '>' . static::$LE;
                 }
 
-                // Allow for bypassing the Content-Disposition header
+                //Allow for bypassing the Content-Disposition header
                 if (!empty($disposition)) {
                     $encoded_name = $this->encodeHeader($this->secureHeader($name));
                     if (!empty($encoded_name)) {
@@ -3145,7 +3233,7 @@
                     $mime[] = static::$LE;
                 }
 
-                // Encode as string attachment
+                //Encode as string attachment
                 if ($bString) {
                     $mime[] = $this->encodeString($string, $encoding);
                 } else {
@@ -3221,7 +3309,7 @@
             case static::ENCODING_7BIT:
             case static::ENCODING_8BIT:
                 $encoded = static::normalizeBreaks($str);
-                // Make sure it ends with a line break
+                //Make sure it ends with a line break
                 if (substr($encoded, -(strlen(static::$LE))) !== static::$LE) {
                     $encoded .= static::$LE;
                 }
@@ -3259,7 +3347,7 @@
         switch (strtolower($position)) {
             case 'phrase':
                 if (!preg_match('/[\200-\377]/', $str)) {
-                    // Can't use addslashes as we don't know the value of magic_quotes_sybase
+                    //Can't use addslashes as we don't know the value of magic_quotes_sybase
                     $encoded = addcslashes($str, "\0..\37\177\\\"");
                     if (($str === $encoded) && !preg_match('/[^A-Za-z0-9!#$%&\'*+\/=?^_`{|}~ -]/', $str)) {
                         return $encoded;
@@ -3285,7 +3373,7 @@
             $charset = static::CHARSET_ASCII;
         }
 
-        // Q/B encoding adds 8 chars and the charset ("` =?<charset>?[QB]?<content>?=`").
+        //Q/B encoding adds 8 chars and the charset ("` =?<charset>?[QB]?<content>?=`").
         $overhead = 8 + strlen($charset);
 
         if ('mail' === $this->Mailer) {
@@ -3294,26 +3382,26 @@
             $maxlen = static::MAX_LINE_LENGTH - $overhead;
         }
 
-        // Select the encoding that produces the shortest output and/or prevents corruption.
+        //Select the encoding that produces the shortest output and/or prevents corruption.
         if ($matchcount > strlen($str) / 3) {
-            // More than 1/3 of the content needs encoding, use B-encode.
+            //More than 1/3 of the content needs encoding, use B-encode.
             $encoding = 'B';
         } elseif ($matchcount > 0) {
-            // Less than 1/3 of the content needs encoding, use Q-encode.
+            //Less than 1/3 of the content needs encoding, use Q-encode.
             $encoding = 'Q';
         } elseif (strlen($str) > $maxlen) {
-            // No encoding needed, but value exceeds max line length, use Q-encode to prevent corruption.
+            //No encoding needed, but value exceeds max line length, use Q-encode to prevent corruption.
             $encoding = 'Q';
         } else {
-            // No reformatting needed
+            //No reformatting needed
             $encoding = false;
         }
 
         switch ($encoding) {
             case 'B':
                 if ($this->hasMultiBytes($str)) {
-                    // Use a custom function which correctly encodes and wraps long
-                    // multibyte strings without breaking lines within a character
+                    //Use a custom function which correctly encodes and wraps long
+                    //multibyte strings without breaking lines within a character
                     $encoded = $this->base64EncodeWrapMB($str, "\n");
                 } else {
                     $encoded = base64_encode($str);
@@ -3348,7 +3436,7 @@
             return strlen($str) > mb_strlen($str, $this->CharSet);
         }
 
-        // Assume no multibytes (we can't handle without mbstring functions anyway)
+        //Assume no multibytes (we can't handle without mbstring functions anyway)
         return false;
     }
 
@@ -3386,11 +3474,11 @@
         }
 
         $mb_length = mb_strlen($str, $this->CharSet);
-        // Each line must have length <= 75, including $start and $end
+        //Each line must have length <= 75, including $start and $end
         $length = 75 - strlen($start) - strlen($end);
-        // Average multi-byte ratio
+        //Average multi-byte ratio
         $ratio = $mb_length / strlen($str);
-        // Base64 has a 4:3 ratio
+        //Base64 has a 4:3 ratio
         $avgLength = floor($length * $ratio * .75);
 
         $offset = 0;
@@ -3405,7 +3493,7 @@
             $encoded .= $chunk . $linebreak;
         }
 
-        // Chomp the last linefeed
+        //Chomp the last linefeed
         return substr($encoded, 0, -strlen($linebreak));
     }
 
@@ -3434,12 +3522,12 @@
      */
     public function encodeQ($str, $position = 'text')
     {
-        // There should not be any EOL in the string
+        //There should not be any EOL in the string
         $pattern = '';
         $encoded = str_replace(["\r", "\n"], '', $str);
         switch (strtolower($position)) {
             case 'phrase':
-                // RFC 2047 section 5.3
+                //RFC 2047 section 5.3
                 $pattern = '^A-Za-z0-9!*+\/ -';
                 break;
             /*
@@ -3452,15 +3540,15 @@
             /* Intentional fall through */
             case 'text':
             default:
-                // RFC 2047 section 5.1
-                // Replace every high ascii, control, =, ? and _ characters
+                //RFC 2047 section 5.1
+                //Replace every high ascii, control, =, ? and _ characters
                 $pattern = '\000-\011\013\014\016-\037\075\077\137\177-\377' . $pattern;
                 break;
         }
         $matches = [];
         if (preg_match_all("/[{$pattern}]/", $encoded, $matches)) {
-            // If the string contains an '=', make sure it's the first thing we replace
-            // so as to avoid double-encoding
+            //If the string contains an '=', make sure it's the first thing we replace
+            //so as to avoid double-encoding
             $eqkey = array_search('=', $matches[0], true);
             if (false !== $eqkey) {
                 unset($matches[0][$eqkey]);
@@ -3470,8 +3558,8 @@
                 $encoded = str_replace($char, '=' . sprintf('%02X', ord($char)), $encoded);
             }
         }
-        // Replace spaces with _ (more readable than =20)
-        // RFC 2047 section 4.2(2)
+        //Replace spaces with _ (more readable than =20)
+        //RFC 2047 section 4.2(2)
         return str_replace(' ', '_', $encoded);
     }
 
@@ -3498,7 +3586,7 @@
         $disposition = 'attachment'
     ) {
         try {
-            // If a MIME type is not specified, try to work it out from the file name
+            //If a MIME type is not specified, try to work it out from the file name
             if ('' === $type) {
                 $type = static::filenameToType($filename);
             }
@@ -3507,14 +3595,14 @@
                 throw new Exception($this->lang('encoding') . $encoding);
             }
 
-            // Append to $attachment array
+            //Append to $attachment array
             $this->attachment[] = [
                 0 => $string,
                 1 => $filename,
                 2 => static::mb_pathinfo($filename, PATHINFO_BASENAME),
                 3 => $encoding,
                 4 => $type,
-                5 => true, // isStringAttachment
+                5 => true, //isStringAttachment
                 6 => $disposition,
                 7 => 0,
             ];
@@ -3565,7 +3653,7 @@
                 throw new Exception($this->lang('file_access') . $path, self::STOP_CONTINUE);
             }
 
-            // If a MIME type is not specified, try to work it out from the file name
+            //If a MIME type is not specified, try to work it out from the file name
             if ('' === $type) {
                 $type = static::filenameToType($path);
             }
@@ -3579,14 +3667,14 @@
                 $name = $filename;
             }
 
-            // Append to $attachment array
+            //Append to $attachment array
             $this->attachment[] = [
                 0 => $path,
                 1 => $filename,
                 2 => $name,
                 3 => $encoding,
                 4 => $type,
-                5 => false, // isStringAttachment
+                5 => false, //isStringAttachment
                 6 => $disposition,
                 7 => $cid,
             ];
@@ -3631,7 +3719,7 @@
         $disposition = 'inline'
     ) {
         try {
-            // If a MIME type is not specified, try to work it out from the name
+            //If a MIME type is not specified, try to work it out from the name
             if ('' === $type && !empty($name)) {
                 $type = static::filenameToType($name);
             }
@@ -3640,14 +3728,14 @@
                 throw new Exception($this->lang('encoding') . $encoding);
             }
 
-            // Append to $attachment array
+            //Append to $attachment array
             $this->attachment[] = [
                 0 => $string,
                 1 => $name,
                 2 => $name,
                 3 => $encoding,
                 4 => $type,
-                5 => true, // isStringAttachment
+                5 => true, //isStringAttachment
                 6 => $disposition,
                 7 => $cid,
             ];
@@ -3867,8 +3955,8 @@
      */
     public static function rfcDate()
     {
-        // Set the time zone to whatever the default is to avoid 500 errors
-        // Will default to UTC if it's not set properly in php.ini
+        //Set the time zone to whatever the default is to avoid 500 errors
+        //Will default to UTC if it's not set properly in php.ini
         date_default_timezone_set(@date_default_timezone_get());
 
         return date('D, j M Y H:i:s O');
@@ -3946,13 +4034,13 @@
     protected function lang($key)
     {
         if (count($this->language) < 1) {
-            $this->setLanguage(); // set the default language
+            $this->setLanguage(); //Set the default language
         }
 
         if (array_key_exists($key, $this->language)) {
             if ('smtp_connect_failed' === $key) {
-                //Include a link to troubleshooting docs on SMTP connection failure
-                //this is by far the biggest cause of support questions
+                //Include a link to troubleshooting docs on SMTP connection failure.
+                //This is by far the biggest cause of support questions
                 //but it's usually not PHPMailer's fault.
                 return $this->language[$key] . ' https://github.com/PHPMailer/PHPMailer/wiki/Troubleshooting';
             }
@@ -3987,7 +4075,7 @@
     public function addCustomHeader($name, $value = null)
     {
         if (null === $value && strpos($name, ':') !== false) {
-            // Value passed in as name:value
+            //Value passed in as name:value
             list($name, $value) = explode(':', $name, 2);
         }
         $name = trim($name);
@@ -4041,11 +4129,11 @@
         preg_match_all('/(?<!-)(src|background)=["\'](.*)["\']/Ui', $message, $images);
         if (array_key_exists(2, $images)) {
             if (strlen($basedir) > 1 && '/' !== substr($basedir, -1)) {
-                // Ensure $basedir has a trailing /
+                //Ensure $basedir has a trailing /
                 $basedir .= '/';
             }
             foreach ($images[2] as $imgindex => $url) {
-                // Convert data URIs into embedded images
+                //Convert data URIs into embedded images
                 //e.g. "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="
                 $match = [];
                 if (preg_match('#^data:(image/(?:jpe?g|gif|png));?(base64)?,(.+)#', $url, $match)) {
@@ -4059,7 +4147,7 @@
                     }
                     //Hash the decoded data, not the URL, so that the same data-URI image used in multiple places
                     //will only be embedded once, even if it used a different encoding
-                    $cid = substr(hash('sha256', $data), 0, 32) . '@phpmailer.0'; // RFC2392 S 2
+                    $cid = substr(hash('sha256', $data), 0, 32) . '@phpmailer.0'; //RFC2392 S 2
 
                     if (!$this->cidExists($cid)) {
                         $this->addStringEmbeddedImage(
@@ -4078,13 +4166,13 @@
                     continue;
                 }
                 if (
-                    // Only process relative URLs if a basedir is provided (i.e. no absolute local paths)
+                    //Only process relative URLs if a basedir is provided (i.e. no absolute local paths)
                     !empty($basedir)
-                    // Ignore URLs containing parent dir traversal (..)
+                    //Ignore URLs containing parent dir traversal (..)
                     && (strpos($url, '..') === false)
-                    // Do not change urls that are already inline images
+                    //Do not change urls that are already inline images
                     && 0 !== strpos($url, 'cid:')
-                    // Do not change absolute URLs, including anonymous protocol
+                    //Do not change absolute URLs, including anonymous protocol
                     && !preg_match('#^[a-z][a-z0-9+.-]*:?//#i', $url)
                 ) {
                     $filename = static::mb_pathinfo($url, PATHINFO_BASENAME);
@@ -4092,7 +4180,7 @@
                     if ('.' === $directory) {
                         $directory = '';
                     }
-                    // RFC2392 S 2
+                    //RFC2392 S 2
                     $cid = substr(hash('sha256', $url), 0, 32) . '@phpmailer.0';
                     if (strlen($basedir) > 1 && '/' !== substr($basedir, -1)) {
                         $basedir .= '/';
@@ -4119,7 +4207,7 @@
             }
         }
         $this->isHTML();
-        // Convert all message body line breaks to LE, makes quoted-printable encoding work much better
+        //Convert all message body line breaks to LE, makes quoted-printable encoding work much better
         $this->Body = static::normalizeBreaks($message);
         $this->AltBody = static::normalizeBreaks($this->html2text($message, $advanced));
         if (!$this->alternativeExists()) {
@@ -4138,9 +4226,9 @@
      * Example usage:
      *
      * ```php
-     * // Use default conversion
+     * //Use default conversion
      * $plain = $mail->html2text($html);
-     * // Use your own custom converter
+     * //Use your own custom converter
      * $plain = $mail->html2text($html, function($html) {
      *     $converter = new MyHtml2text($html);
      *     return $converter->get_text();
@@ -4307,7 +4395,7 @@
      */
     public static function filenameToType($filename)
     {
-        // In case the path is a URL, strip any query string before getting extension
+        //In case the path is a URL, strip any query string before getting extension
         $qpos = strpos($filename, '?');
         if (false !== $qpos) {
             $filename = substr($filename, 0, $qpos);
@@ -4418,9 +4506,9 @@
         if (null === $breaktype) {
             $breaktype = static::$LE;
         }
-        // Normalise to \n
+        //Normalise to \n
         $text = str_replace([self::CRLF, "\r"], "\n", $text);
-        // Now convert LE as needed
+        //Now convert LE as needed
         if ("\n" !== $breaktype) {
             $text = str_replace("\n", $breaktype, $text);
         }
@@ -4526,13 +4614,13 @@
             $privKey = openssl_pkey_get_private($privKeyStr);
         }
         if (openssl_sign($signHeader, $signature, $privKey, 'sha256WithRSAEncryption')) {
-            if (PHP_MAJOR_VERSION < 8) {
+            if (\PHP_MAJOR_VERSION < 8) {
                 openssl_pkey_free($privKey);
             }
 
             return base64_encode($signature);
         }
-        if (PHP_MAJOR_VERSION < 8) {
+        if (\PHP_MAJOR_VERSION < 8) {
             openssl_pkey_free($privKey);
         }
 
@@ -4599,7 +4687,7 @@
         if (empty($body)) {
             return self::CRLF;
         }
-        // Normalize line endings to CRLF
+        //Normalize line endings to CRLF
         $body = static::normalizeBreaks($body, self::CRLF);
 
         //Reduce multiple trailing line breaks to a single one
@@ -4619,9 +4707,9 @@
      */
     public function DKIM_Add($headers_line, $subject, $body)
     {
-        $DKIMsignatureType = 'rsa-sha256'; // Signature & hash algorithms
-        $DKIMcanonicalization = 'relaxed/simple'; // Canonicalization methods of header & body
-        $DKIMquery = 'dns/txt'; // Query method
+        $DKIMsignatureType = 'rsa-sha256'; //Signature & hash algorithms
+        $DKIMcanonicalization = 'relaxed/simple'; //Canonicalization methods of header & body
+        $DKIMquery = 'dns/txt'; //Query method
         $DKIMtime = time();
         //Always sign these headers without being asked
         //Recommended list from https://tools.ietf.org/html/rfc6376#section-5.4.1
@@ -4722,7 +4810,8 @@
         $headerKeys = ' h=' . implode(':', $headersToSignKeys) . ';' . static::$LE;
         $headerValues = implode(static::$LE, $headersToSign);
         $body = $this->DKIM_BodyC($body);
-        $DKIMb64 = base64_encode(pack('H*', hash('sha256', $body))); // Base64 of packed binary SHA-256 hash of body
+        //Base64 of packed binary SHA-256 hash of body
+        $DKIMb64 = base64_encode(pack('H*', hash('sha256', $body)));
         $ident = '';
         if ('' !== $this->DKIM_identity) {
             $ident = ' i=' . $this->DKIM_identity . ';' . static::$LE;