处理自动换行的电子邮件(Content-Type:text / plain)

时间:2012-04-04 16:49:09

标签: php email

我正在尝试将电子邮件处理到我的应用程序中,一切似乎都能正常工作,直到我从邮件服务器强制执行邮件文本自动换行的用户那里收到电子邮件。我知道自动换行是RFC规范的一部分,所以我只是寻找最好的方法来处理它以获得一个很好的显示消息。

原始电子邮件:

  

这是我的主要问题。当我通过电子邮件发送消息时,文本很奇怪。它几乎看起来好像消息本身已被破坏。我不确定为什么会这样,因为我原来的电子邮件看起来不像那样。

以下是收到的电子邮件的样子(标有CRLF以显示邮件服务器插入的位置):

  

这是我的主要问题。当我通过电子邮件发送消息时,文本被分解为CRLF
  奇怪。它几乎看起来好像消息本身已被破坏。我不确定CRLF
  为什么会这样,因为我原来的电子邮件看起来不像CRLF
  这一点。

我的处理代码贯穿以下内容,然后将结果插入数据库。

$dirty_string = nl2br($dirty_string);
$config = HTMLPurifier_Config::createDefault();
$config->set('AutoFormat.RemoveEmpty', 'true');
$config->set('AutoFormat.RemoveEmpty.RemoveNbsp', 'true');
$config->set('HTML.Allowed', 'a[href],br,p');
$purifier = new HTMLPurifier($config);
$clean_string = $purifier->purify($dirty_string);

以下是显示的结果。如果我的页面上的div对于该行不够宽,浏览器将自动自动换行,但是来自nl2br()的换行导致下一行变短。

  

这是我的主要问题。当我通过电子邮件发送消息时,文本为
  分手了   奇怪。它几乎看起来就像消息本身一样   破碎。我不确定   为什么会出现这种情况,因为我原来的电子邮件看起来不像什么   这一点。

我想也许我可以将双CRLF更改为新的段落并删除所有单个CRLF以将这些行连接到单行,其中自动换行将正确显示。但如果有人在电子邮件中发布以下项目符号列表,则会破坏列表。

  

这是我的列表CRLF
   - 第1项CRLF
   - 第2项CRLF
  等...

任何帮助都会非常感激。

5 个答案:

答案 0 :(得分:1)

邮件解析可能是一个看似简单的问题的典型示例,但实际上是填充了破坏简单解析器的古怪边缘情况。但是,它也不是一个新问题,因此有很多现有的解决方案可以正常工作。一些选择:

也许你已经编写了一个很棒的解析器,只需要一点点改变即可完美,但更有可能通过使用已有的工具来节省你自己的时间和心痛。

答案 1 :(得分:0)

这个怎么样:对于下一行包含单词并且不以空白字符开头的任何行(例如列表中的缩进),检查行的长度是否在65到80个字符之间。如果是,则删除尾随CR(如果该行的末尾不包含空格或标点符号,则添加空格)。这将获得大部分自动换行案例,并将大部分列表单独留下。

答案 2 :(得分:0)

您可以尝试使用TinyMCE编辑器查看电子邮件。它会正确格式化。我已经使用TinyMCE几次输入数据并将其保存到数据库中,每次检索数据后它都正确显示它,无论格式化多么奇怪。

答案 3 :(得分:0)

这样的黑客怎么样:在78的倍数的任何位置删除CLRF字符(+说5个字符来说明这个事实:the mail server won't just cut a line mid-word)。

所以你会在这些位置寻找CLRF字符:

  • 78 79 80 81 82 83 AND
  • 156 157 158 159 160 161 AND
  • 等等。

这当然假设最长的单词长度为5个字符。您应该根据需要解析的电子邮件进行调整。

答案 4 :(得分:0)

这是一个能很好地完成工作的功能:

function PlaintextEmailBrokenLineCombine($lineSet, $startIndex = 0) {
    $result = '';
    $lineCount = count($lineSet);
    for($i=$startIndex; $i < $lineCount; $i++) {
        $thisLine = $lineSet[$i];
        $nextLine = ($i < $lineCount-1 ? $lineSet[$i+1] : '');
        $nextLineFirstWord = substr($nextLine, 0, strpos($nextLine, ' '));

        $lineSeparator = "\n"; // we assume until we detect invocation of the 78char rule
        if(strlen($thisLine) + strlen($nextLineFirstWord) + 1 > 75) {
            // A line break was PROBABLY put in here where a space once was, so switch back:
            $lineSeparator = ' ';
        }
        $result .= $thisLine . ($i == $lineCount-1 ? '' : $lineSeparator); // no separator for the last line
    }
    return $result;
}

这有点深奥,因为它期望来自纯文本电子邮件的一系列行。这是用法:

$Parser = new MimeMailParser();
$Parser->setText($rawEmailText); 
$plaintext = $Parser->getMessageBody('text'); // or however you get it, many ways
$lineSet = explode("\n", $plaintext);
$niceText = PlaintextEmailBrokenLineCombine($lineSet);

$ niceText是你想要的:它是一个非常准确的方法来获取你想要的文本与那些讨厌的服务器添加的换行符,并替换为原始空格。