如何使用PHP IMAP获取不含回复内容的邮件正文?
仅提取原始邮件正文(排除回复内容)的解决方案
核心思路
在无明确视觉分割标记的情况下,需依赖邮件的结构化元数据和文本语义特征区分原始内容与回复内容,以下是可落地的实操方法:
1. 优先提取纯文本格式内容
通过imap_fetchstructure解析邮件结构,优先获取text/plain类型内容(比HTML更易处理),避免直接处理混合了原始与回复内容的HTML:
$structure = imap_fetchstructure($imap, $msg_num); // 递归遍历邮件结构,提取text/plain部分 function getPlainText($imap, $msgNum, $part) { if ($part->type == 0) { // 匹配text/plain类型 $encoding = $part->encoding; $text = imap_fetchbody($imap, $msgNum, $part->part_number); // 解码不同编码的内容 switch($encoding) { case 3: return imap_base64($text); case 4: return imap_qprint($text); default: return $text; } } if ($part->parts) { foreach($part->parts as $subpart) { $result = getPlainText($imap, $msgNum, $subpart); if ($result) return $result; } } return ""; } $plainText = getPlainText($imap, $msg_num, $structure);
2. 基于回复的通用文本模式截断
回复内容通常带有固定格式特征,可通过正则匹配这些标记,截断原始内容之后的部分:
// 覆盖主流邮件客户端的回复起始标记 $replyPatterns = [ '/On\s+\w+\s+\d+,\s+\d+\s+at\s+\d+:\d+.*wrote:/i', '/--------\s*Original Message\s*--------/i', '/^\s*From:\s+.+$/m' // 匹配回复中重复的发件人行 ]; // 找到第一个回复标记,保留标记之前的内容 foreach ($replyPatterns as $pattern) { preg_match($pattern, $plainText, $matches, PREG_OFFSET_CAPTURE); if (!empty($matches)) { $plainText = trim(substr($plainText, 0, $matches[0][1])); break; } } // 额外移除所有带>引用符号的行 $plainText = preg_replace('/^\s*>.*\n?/m', '', $plainText);
3. 结合邮件头信息过滤冗余内容
对比邮件的From/To头信息,过滤回复中重复出现的发件人、收件人相关段落:
$headers = imap_headerinfo($imap, $msg_num); $fromAddr = $headers->from[0]->mailbox . "@" . $headers->from[0]->host; $toAddr = $headers->to[0]->mailbox . "@" . $headers->to[0]->host; // 移除包含发件人/收件人邮箱的冗余行 $plainText = preg_replace("/.*($fromAddr|$toAddr).*\n?/i", '', $plainText);
4. HTML格式内容的特殊处理
若必须处理text/html格式,先将HTML转成纯文本再按上述方法处理:
function htmlToPlain($html) { $text = strip_tags($html); $text = preg_replace('/[\r\n]+/', "\n", $text); $text = preg_replace('/\s+/', ' ', $text); return trim($text); } // 提取并转换text/html内容 function getHtmlPlainText($imap, $msgNum, $part) { if ($part->type == 1) { // 匹配text/html类型 $encoding = $part->encoding; $html = imap_fetchbody($imap, $msgNum, $part->part_number); if ($encoding == 3) $html = imap_base64($html); if ($encoding == 4) $html = imap_qprint($html); return htmlToPlain($html); } if ($part->parts) { foreach($part->parts as $subpart) { $result = getHtmlPlainText($imap, $msgNum, $subpart); if ($result) return $result; } } return ""; } $htmlPlain = getHtmlPlainText($imap, $msg_num, $structure);
注意事项
- 不同邮件客户端的回复格式差异较大,需组合多种正则模式覆盖更多场景
- 对于完全无格式标记的手动粘贴式回复,只能通过语义连贯性分析处理,这类场景需依赖AI辅助,实现成本较高
内容的提问来源于stack exchange,提问作者mustafa
相关产品推荐
相关产品推荐

