簡體   English   中英

處理自動換行的電子郵件(內容類型:文本/純文本)

[英]Processing e-mails that are word wrapped (Content-Type: text/plain)

我正在嘗試將電子郵件處理到我的應用程序中,並且一切似乎都正常工作,直到我收到一封來自用戶的電子郵件,該用戶的郵件服務器正在強制對郵件文本進行自動換行。 我知道自動換行是 RFC 規范的一部分,所以我只是在尋找處理它的最佳方法以獲得顯示良好的消息。

原始電子郵件:

這是我的主要問題。 當我 email 一條消息時,文本被分解得相當奇怪。 它幾乎看起來好像消息本身被破壞了。 我不確定為什么會這樣,因為我原來的 email 看起來一點也不像。

這是收到的電子郵件的樣子(標有 CRLF 以顯示郵件服務器插入它們的位置):

這是我的主要問題。 當我email發消息時,文字被打散而CRLF
奇怪。 它幾乎看起來好像消息本身被破壞了。 我不確定 CRLF
為什么會這樣,因為我原來的 email 看起來一點也不像 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() 的換行符會導致下一行變短。

這是我的主要問題。 當我email留言時,正文是
寧願分手
奇怪。 它幾乎看起來好像消息本身是
破碎的。 我不確定
為什么會這樣,因為我原來的 email 看起來
什么都不像
那。

我想也許我可以將雙 CRLF 更改為新段落並去除所有單個 CRLF 以將這些行連接成一個自動換行可以正確顯示的單行。 但是,如果有人在電子郵件中發布了以下項目符號列表,則會破壞列表。

這是我的清單 CRLF
- 第 1 項 CRLF
- 第 2 項 CRLF
ETC...

任何幫助將不勝感激。

郵件解析可能是一個典型的問題示例,它看起來很簡單,但實際上充滿了破壞簡單解析器的古怪邊緣情況。 然而,這也不完全是一個新問題,所以有很多現有的解決方案都可以正常工作。 一些選項:

也許您已經編寫了一個很棒的解析器,只需要這個小改動就可以完美,但更有可能的是,通過使用現有的工具來完成這項工作,您會節省很多時間和心痛。

這個怎么樣:對於下一行包含單詞並且不以空白字符開頭的任何行(例如列表中的縮進),檢查該行的長度是否在 65 到 80 個字符之間。 如果是,請刪除尾隨的 CR(如果行尾不包含空格或標點符號,則添加一個空格)。 這將得到你的大部分自動換行情況,而不會影響你的大部分列表。

您可以嘗試使用TinyMCE編輯器查看電子郵件信息。 它將正確格式化。 我已經使用 TinyMCE 幾次輸入數據並將其保存到數據庫中,無論格式多么奇怪,每次我檢索數據后它都會正確顯示。

像這樣的 hack 怎么樣:刪除 78 的倍數的任何位置的 CLRF 字符(+ 說 5 個字符來說明這個事實: the mail server won't just cut a line mid-word )。

所以你會在這些位置尋找 CLRF 字符:

  • 787980818283
  • 156157158159160161
  • 很快。

這當然是假設最長的單詞長度為 5 個字符。 您應該根據需要解析的電子郵件進行調整。

這是一個 function 可以很好地完成這項工作:

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;
}

它有點深奧,因為它需要來自純文本 email 的行數組。這是用法:

$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 是你想要的:這是一種非常准確的方式來獲取你想要的文本,而那些討厭的服務器添加的換行符消失了,並被原來的空格所取代。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM