如何读取包含HTML、文本及图片的完整邮件正文?
如何用PHP IMAP完整读取邮件正文(含HTML、图片)
嘿,你的问题我懂了——当前脚本只抓取了邮件的纯文本部分(对应MIME结构里的1.1段),所以看不到HTML内容和图片。要完整读取所有内容,得处理邮件的MIME多部分结构,因为现代邮件通常是由多个部分组成的(纯文本、HTML、内嵌资源、附件等)。我给你整理了一套可行的方案:
核心思路
邮件的内容是按MIME类型拆分的,我们需要:
- 递归解析邮件的每个MIME部分
- 区分纯文本、HTML、内嵌图片(带
cid:标识的资源) - 处理内嵌图片,把HTML里的
cid:引用替换成可直接显示的内容(比如base64编码)
完整代码示例
<?php // 连接IMAP服务器(Gmail需开启IMAP,开启2FA的话要用应用专用密码) $msgStream = imap_open('{imap.gmail.com:993/imap/ssl/novalidate-cert}INBOX', 'abc@gmail.com', '你的登录密码/应用专用密码'); if (!$msgStream) { die('IMAP连接失败: ' . imap_last_error()); } // 搜索未读邮件 $emails = imap_search($msgStream, 'UNSEEN'); if (!empty($emails)) { foreach ($emails as $mailNumber) { // 获取邮件概览信息 $overview = imap_fetch_overview($msgStream, $mailNumber, 0); echo "<h3>邮件主题: " . $overview[0]->subject . "</h3>"; // 初始化内容存储数组 $emailContent = [ 'text' => '', 'html' => '', 'inline_images' => [] ]; // 获取邮件完整MIME结构并递归解析 $structure = imap_fetchstructure($msgStream, $mailNumber); parseMimePart($msgStream, $mailNumber, $structure, $emailContent); // 替换HTML中的内嵌图片引用(cid转base64) if (!empty($emailContent['html']) && !empty($emailContent['inline_images'])) { foreach ($emailContent['inline_images'] as $cid => $imageData) { $emailContent['html'] = str_replace( 'cid:' . $cid, 'data:image/' . strtolower($imageData['type']) . ';base64,' . $imageData['content'], $emailContent['html'] ); } } // 输出解析后的内容 echo "<h4>纯文本内容:</h4>"; echo "<pre>" . htmlspecialchars($emailContent['text']) . "</pre>"; echo "<h4>HTML内容:</h4>"; echo $emailContent['html']; // 保持邮件为未读状态(根据需求调整) imap_clearflag_full($msgStream, $mailNumber, "\\Seen"); } } else { echo "<h2>No new mail found</h2>"; } imap_close($msgStream); /** * 递归解析MIME邮件部分 */ function parseMimePart($stream, $mailNumber, $part, &$content) { // 处理纯文本部分 if ($part->type == 0) { $encoding = $part->encoding ?? 0; $text = imap_fetchbody($stream, $mailNumber, $part->number); $content['text'] .= decodeImapContent($text, $encoding); } // 处理HTML部分 elseif ($part->type == 1) { $encoding = $part->encoding ?? 0; $html = imap_fetchbody($stream, $mailNumber, $part->number); $content['html'] .= decodeImapContent($html, $encoding); } // 处理多部分嵌套邮件(递归子部分) elseif ($part->type == 2) { foreach ($part->parts as $subPart) { parseMimePart($stream, $mailNumber, $subPart, $content); } } // 处理内嵌图片(标记为inline的附件) elseif ($part->type == 3 && isset($part->disposition) && strtolower($part->disposition) == 'inline') { // 提取图片的Content-ID(cid) $cid = ''; if (isset($part->dparameters)) { foreach ($part->dparameters as $param) { if (strtolower($param->attribute) == 'filename') { $cid = $param->value; } } } if (empty($cid) && isset($part->parameters)) { foreach ($part->parameters as $param) { if (strtolower($param->attribute) == 'name') { $cid = $param->value; } } } // 解码图片内容并存储 $encoding = $part->encoding ?? 0; $imageRaw = imap_fetchbody($stream, $mailNumber, $part->number); $content['inline_images'][$cid] = [ 'type' => $part->subtype, 'content' => decodeImapContent($imageRaw, $encoding, true) ]; } } /** * 解码不同编码的IMAP内容 */ function decodeImapContent($content, $encoding, $returnBase64 = false) { switch ($encoding) { case 3: // BASE64编码 $decoded = base64_decode($content); return $returnBase64 ? base64_encode($decoded) : $decoded; case 4: // QUOTED-PRINTABLE编码 return quoted_printable_decode($content); case 0: // 7BIT case 1: // 8BIT default: return $content; } } ?>
关键说明
- MIME结构解析:通过
imap_fetchstructure()获取邮件的完整结构,递归遍历每个子部分,精准区分纯文本、HTML和内嵌资源。 - 内容解码:邮件内容常用BASE64或QUOTED-PRINTABLE编码,
decodeImapContent函数统一处理解码逻辑,确保内容正常显示。 - 内嵌图片处理:把HTML中
cid:开头的引用替换成base64编码的图片数据,这样HTML可以直接渲染图片,无需额外存储文件。 - Gmail配置提示:如果你的Gmail开启了两步验证,必须使用应用专用密码登录;同时要在Gmail设置中开启IMAP服务。
内容的提问来源于stack exchange,提问作者Paritosh Mahale
相关产品推荐
相关产品推荐

