电子邮件主题中断间距中的重音词 - 如何停止此操作?

Adr*_*zza 7 php email character-encoding email-headers

我们有一个自定义的php电子邮件营销应用程序,还有一个有趣的问题:如果邮件的主题行包含带重音的单词,它会"吞下"它与下一个单词之间的空格.一个例子:短语

ÁngelRíosescuchay sorprende

显示(至少通过gmail和lotus notes)

ÁngelRíosescuchay sorprende

消息源中的特定行显示:

Subject: =?ISO-8859-1?Q?=C1ngel?= =?ISO-8859-1?Q?R=EDos?= escucha y sorprende

(半满标头):

Delivered-To: me@gmail.com
Received: {elided}
Return-Path: <return@path>
Received: {elided}
Received: (qmail 23734 invoked by uid 48); 18 Aug 2009 13:51:14 -0000
Date: 18 Aug 2009 13:51:14 -0000
To: "Adriano" <me@gmail.com>
Subject: =?ISO-8859-1?Q?=C1ngel?= =?ISO-8859-1?Q?R=EDos?= escucha y sorprende
MIME-Version: 1.0
From: {elided}
X-Mailer: PHP
X-Lista: 1290
X-ID: 48163
Content-Type: text/html; charset="ISO-8859-1"
Content-Transfer-Encoding: quoted-printable
Message-ID: <kokrte.rpq06m@example.com>
Run Code Online (Sandbox Code Playgroud)

编辑:

该应用程序使用旧版本的Html Mime Mail来准备消息,我将尝试升级到更新的版本.无论如何,这是编码主题的函数:

/**
 * Function to encode a header if necessary
 * according to RFC2047
 */
function _encodeHeader($input, $charset = 'ISO-8859-1')
{
    preg_match_all('/(\w*[\x80-\xFF]+\w*)/', $input, $matches);
    foreach ($matches[1] as $value) {
        $replacement = preg_replace('/([\x80-\xFF])/e', '"=" . strtoupper(dechex(ord("\1")))', $value);
        $input = str_replace($value, '=?' . $charset . '?Q?' . $replacement . '?=', $input);
    }

    return $input;
}
Run Code Online (Sandbox Code Playgroud)

这里是主题编码的代码:

if (!empty($this->headers['Subject'])) {
    $subject = $this->_encodeHeader($this->headers['Subject'],
                                    $this->build_params['head_charset']);
    unset($this->headers['Subject']);
}
Run Code Online (Sandbox Code Playgroud)

包起来

问题是,实际上,该程序并未对所述案例中的空间进行编码.经过轻微修改(在对该答案的评论中提到)后,接受的答案解决了我的问题,因为PHP的已安装版本不支持特定的实现细节.

最后的答案

虽然接受的答案确实解决了这个问题,但我们发现它与数千封电子邮件相结合,正在咀嚼服务器上的所有可用内存.我检查了这个电子邮件框架的原始开发者的网站,发现该功能已更新为以下内容:

function _encodeHeader($input, $charset = 'ISO-8859-1') {
        preg_match_all('/(\w*[\x80-\xFF]+\w*)/', $input, $matches);
        foreach ($matches[1] as $value) {
            $replacement = preg_replace('/([\x80-\xFF])/e', '"=" . strtoupper(dechex(ord("\1")))', $value);
            $input = str_replace($value, $replacement , $input);
        }
        if (!empty($matches[1])) {
            $input = str_replace(' ', '=20', $input);
            $input = '=?' . $charset .  '?Q?' .$input . '?=';
        }
        return $input;
    }
Run Code Online (Sandbox Code Playgroud)

它整齐地解决了这个问题,并保持在mem限制之下.

Gum*_*mbo 5

您还需要对两者之间的空间进行编码(请参阅RFC 2047):

(=?ISO-8859-1?Q?a?= =?ISO-8859-1?Q?b?=)     (ab)
Run Code Online (Sandbox Code Playgroud)

不显示相邻'编码字'之间的空白区域.

[...]

(=?ISO-8859-1?Q?a_b?=)                      (a b)
Run Code Online (Sandbox Code Playgroud)

为了使SPACE显示在编码文本的一部分内,空间必须编码为"编码字"的一部分.

(=?ISO-8859-1?Q?a?= =?ISO-8859-2?Q?_b?=)    (a b)
Run Code Online (Sandbox Code Playgroud)

为了使两个编码文本字符串之间显示SPACE,可以将SPACE编码为"编码字"之一的一部分.

所以这应该这样做:

Subject: =?ISO-8859-1?Q?=C1ngel=20R=EDos?= escucha y sorprende
Run Code Online (Sandbox Code Playgroud)

编辑     尝试此功能:

function _encodeHeader($str, $charset='ISO-8859-1')
{
    $words = preg_split('/(\s+)/', $str, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
    $func = create_function('$match', 'return $match[0] === " " ? "_" : sprintf("=%02X", ord($match[0]));');
    $encoded = false;
    foreach ($words as $key => &$word) {
        if (!ctype_space($word)) {
            $tmp = preg_replace_callback('/[^\x21-\x3C\x3E-\x5E\x60-\x7E]/', $func, $word);
            if ($tmp !== $word) {
                if (!$encoded) {
                    $word = '=?'.$charset.'?Q?'.$tmp;
                } else {
                    $word = $tmp;
                    if ($key > 0) {
                        $words[$key-1] = preg_replace_callback('/[^\x21-\x3C\x3E-\x5E\x60-\x7E]/', $func, $words[$key-1]);
                    }
                }
                $encoded = true;
            } else {
                if ($encoded) {
                    $words[$key-2] .= '?=';
                }
                $encoded = false;
            }
        }
    }
    if ($encoded) {
        $words[$key] .= '?=';
    }
    return implode('', $words);
}
Run Code Online (Sandbox Code Playgroud)