MIME 编码的折叠主题标头在调用 mail() 时导致警告

Posted

技术标签:

【中文标题】MIME 编码的折叠主题标头在调用 mail() 时导致警告【英文标题】:MIME encoded folded Subject header results in warning when calling mail() 【发布时间】:2013-04-20 17:05:14 【问题描述】:

当主题标头被 MIME 编码并折叠 mail() 时,会导致 php 警告:

<?php
$mime_subject = "=?ISO-8859-1?B?SWYgeW91IGNhbiByZWFkIHRoaXMgeW8=?=\r\n =?ISO-8859-2?B?dSB1bmRlcnN0YW5kIHRoZSBleGFtcGxlLg==?=";
mail( "name@domain.com", $mime_subject , "Hallo");

=> mail(): Bad parameters to mail() function, mail not sent.

主题行是 RFC2047(第 8 节)中的示例之一。它被折叠成两行,mail() 不喜欢它。由于它在其他主机上运行良好,我怀疑配置错误。但那会是哪一个呢?

PHP 是 5.4.0 版

有什么想法吗?

编辑:

关于 php 配置的更多信息:

'./configure' '--prefix=/home/www/PHP/php-5.4.0' '--with-openssl'
    '--with-zlib-dir=/usr/lib/' '--with-jpeg-dir=/usr/lib/' '--with-mysql'
    '--enable-fastcgi' '--with-informix=/opt/informix'
    '--with-oci8=shared,instantclient,/opt/oracleclient/instantclient,10.2'
    '--enable-pcntl' '--with-gettext' '--with-ldap' '--with-curl'
    '--with-gd' '--with-freetype-dir=/usr/include/freetype2/' '--with-dom'
    '--enable-bcmath' '--enable-soap' '--enable-mbstring'
    '--with-mcrypt=shared,/usr/local/libmcrypt' '--enable-pdo'
    '--with-pdo-mysql' '--enable-zip' '--with-imap' '--with-kerberos'
    '--with-imap-ssl' '--with-ldap-sasl' '--with-icu-dir=/usr' '--enable-intl'

mail.add_x_header   Off Off
mail.force_extra_parameters no value    no value
mail.log    no value    no value
sendmail_from   no value    no value
sendmail_path   /usr/sbin/sendmail -t -i    /usr/sbin/sendmail -t -i 
SMTP    localhost   localhost
smtp_port   25  25

mailparse version 2.1.6

【问题讨论】:

换行的目的是什么?无论如何,您并没有传递任何人类可读的内容,我推测删除它会解决问题。 因为 RFC2047 第 2 节。编码字的语法:“编码字”的长度不得超过 75 个字符,包括“字符集”、“编码”、“编码文本”、和分隔符。如果希望编码的文本多于 75 个字符的“编码字”,则可以使用多个“编码字”(由 CRLF SPACE 分隔)。 (ietf.org/rfc/rfc2047.txt) 是的,但如果这不是 PHP 界面向您公开的内容,则不一定相关。 我不确定我理解你的意思。根据php.net/manual/en/function.mail.php,主题需要遵守2047。我在它工作的其他机器上进行了测试。我只是想知道,为什么它不能在一台机器上工作。 【参考方案1】:

您是正确的,该示例应该只是“我可以阅读”。但是 PHP 文档中的另一个注释提到,一些邮件传输代理会自动将 \n 更改为 \r\n,因此如果您已经提供了 \r\n(变为 \r\r\n),则会导致问题。

因此您可以尝试使用下面的代码(虽然它不符合标准,但您的邮件代理可能会使其符合标准)

<?php
$mime_subject = "=?ISO-8859-1?B?SWYgeW91IGNhbiByZWFkIHRoaXMgeW8=?=\n=?ISO-8859-2?B?dSB1bmRlcnN0YW5kIHRoZSBleGFtcGxlLg==?=";
mail( "name@domain.com", $mime_subject , "Hallo");
?>

PHP 在自己的代码中几乎不会检查有效主题,因此它全部由您的邮件代理处理。

PHP 源代码(只是主题检查,看它没有什么特别的):

if (subject_len > 0) 
  subject_r = estrndup(subject, subject_len);
  for (; subject_len; subject_len--) 
    if (!isspace((unsigned char) subject_r[subject_len - 1])) 
      break;
    
    subject_r[subject_len - 1] = '\0';
  
  for (i = 0; subject_r[i]; i++) 
    if (iscntrl((unsigned char) subject_r[i])) 

      /* According to RFC 822, section 3.1.1 long headers may be separated into
       * parts using CRLF followed at least one linear-white-space character ('\t' or ' ').
       * To prevent these separators from being replaced with a space, we use the
       * SKIP_LONG_HEADER_SEP to skip over them. */

      SKIP_LONG_HEADER_SEP(subject_r, i);
      subject_r[i] = ' ';
    
  
 else 
  subject_r = subject;

【讨论】:

问题出现在 \n 和 \r\n 上。标准中需要额外的空间。我想这是为了检测多行标题。它甚至在您发布的来源中也是如此。 我们正在使用 sendmail。您是否碰巧哪种配置可能导致此错误? 笨蛋,先打空格部分再加代码。删除它。额外的\r 有几个,但根据 qmail 的说法,它最为人所知。您的文件/编码可能是什么?如果使用utf8_encode($subject) 发送呢?检查 ***.com/questions/8171856/… 以获取在 sendmail 上存在编码问题的 python 脚本 没有 UTF-8,只有 ISO-8859-1。仅使用属于 8859-1 一部分的非英语字符(德语变音符号和法语重音字符)。 这是一种猜谜游戏 :) 但是我的服务器有一些与你的不同的设置,如果你可以改变它来测试,可能会让它工作。对我来说,mail.add_x_header 都打开了,sendmail_from 有一个本地值(电子邮件地址),sendmail_path 没有任何值。还设置了mail.log,但我认为这并不重要。但是当然设置日志可以帮助您确定哪里出错了。没有任何设置与您正在做的事情直接相关,但是由于它应该可以正常工作,因此您有时会在最奇怪的地方找到解决方案

以上是关于MIME 编码的折叠主题标头在调用 mail() 时导致警告的主要内容,如果未能解决你的问题,请参考以下文章

解析电子邮件主题标头

将字符串转换为 MIME 标头

标头解析 + MIME

解码 UTF8 电子邮件标头

使用 codeigniter 电子邮件库的主题 > 75 个字符时格式错误的电子邮件主题标头

如何对 MIME 消息中 Content-Disposition 标头的文件名参数值进行编码?