我们有一个自定义的 php 电子邮件营销应用程序,还有一个有趣的问题:
如果邮件的主题行包含带有重音符号的单词,则会“吞掉”该单词与下一个单词之间的空格。
示例:短语
安赫尔·里奥斯·埃斯库查·索普伦德
显示(至少通过 gmail 和 Lotus Notes)为
AngelRíos escucha y sorprende
消息源中的特定行显示:
Subject: =?ISO-8859-1?Q?=C1ngel?= =?ISO-8859-1?Q?R=EDos?= escucha y sorprende
(半完整标题):
Delivered-To: [email protected] /cdn-cgi/l/email-protection
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" <[email protected] /cdn-cgi/l/email-protection>
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: <[email protected] /cdn-cgi/l/email-protection>
EDIT:
该应用程序使用旧版本的 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;
}
这是对主题进行编码的代码:
if (!empty($this->headers['Subject'])) {
$subject = $this->_encodeHeader($this->headers['Subject'],
$this->build_params['head_charset']);
unset($this->headers['Subject']);
}
Wrap-up
问题在于,程序确实没有对上述情况下的空间进行编码。接受的答案 https://stackoverflow.com/questions/1294066/accented-words-in-email-subject-break-spacing-how-do-i-stop-this/1294391#1294391经过轻微修改(在该答案的评论中提到)后解决了我的问题,因为安装的 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;
}
这巧妙地解决了问题并保持在内存限制以下。