PHP IMAP库读取已读/未读邮件返回0结果的解决方法
解决PHP-IMAP使用SEEN/UNSEEN搜索无结果的问题
问题根源
- 连接邮箱时未启用
/readonly模式,导致获取邮件过程中自动将未读邮件标记为已读,后续搜索UNSEEN无结果 - 原代码中HTML表格结构嵌套错误(用
<div class="row">包裹<td>),引发页面渲染异常 getActualContent函数存在未定义变量风险,当匹配不到内容标记时会报错
修正后的完整代码
<!DOCTYPE html> <html> <head> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"> <link rel="stylesheet" href="style.css"> <script> function getEmails() { document.getElementById('dataDivID').style.display = "block"; } </script> </head> <body> <h2>List Emails from inbox of tanzeem@cdit.org using PHP and IMAP</h2> <div id="btnContainer"> <button class="btn active" onclick="getEmails()"> <i class="fa fa-bars"></i>Click to get mails </button> </div> <br> <div id="dataDivID" class="form-container" style="display:none;"> <?php // 开启只读模式,避免自动修改邮件已读状态 $host = '{mail.cdit.org:993/ssl/readonly}INBOX'; $user = 'tanzeem@cdit.org'; $password = 'MYPASSWORD'; // 建立IMAP连接并处理连接错误 $conn = imap_open($host, $user, $password) or die('无法连接到mail.cdit.org: ' . imap_last_error()); // 搜索未读邮件,替换为'SEEN'可搜索已读邮件 $mails = imap_search($conn, 'UNSEEN'); // 处理搜索结果 if ($mails === false) { echo '<p>未找到符合条件的邮件,错误信息:' . implode(', ', imap_errors()) . '</p>'; } elseif ($mails) { $mailOutput = '<table><tr><th>Subject </th><th> From </th><th> Date Time </th> <th> Content </th></tr>'; // 倒序排列,最新邮件显示在顶部 rsort($mails); foreach ($mails as $email_number) { // 使用FT_PEEK参数,避免获取邮件概述时标记为已读 $headers = imap_fetch_overview($conn, $email_number, FT_PEEK); $header = imap_headerinfo($conn, $email_number); $from = $header->from; $fromname = ''; $fromaddress = ''; foreach ($from as $id => $object) { $fromname = $object->personal; $fromaddress = $object->mailbox . "@" . $object->host; } // 获取邮件结构 $structure = imap_fetchstructure($conn, $email_number); $htmlMessage = ''; $message = ''; // 查找HTML格式内容 if (isset($structure->parts) && is_array($structure->parts)) { foreach ($structure->parts as $part) { if ($part->subtype === 'HTML') { $htmlMessage = getDecodedContent($conn, $email_number, $part); break; } } } // 优先使用HTML内容,无HTML则使用纯文本 $message = !empty($htmlMessage) ? $htmlMessage : getDecodedContent($conn, $email_number, $structure); $finalMessage = getActualContent($message); // 修复表格结构:用<tr>正确包裹表格行 $mailOutput.= '<tr>'; $mailOutput.= '<td><span class="columnClass">' . $headers[0]->subject . '</span></td> '; $mailOutput.= '<td><span class="columnClass">' . $fromaddress . '</span></td>'; $mailOutput.= '<td><span class="columnClass">' . $headers[0]->date . '</span></td>'; $mailOutput.= '<td><span class="column">' . $finalMessage . '</span></td>'; $mailOutput.= '</tr>'; } $mailOutput.= '</table>'; echo $mailOutput; } else { echo '<p>未找到符合条件的邮件</p>'; } // 关闭IMAP连接 imap_close($conn); /** * 解码邮件指定部分的内容 * * @param resource $conn IMAP连接资源 * @param int $email_number 邮件编号 * @param object $part 邮件结构的指定部分 * @return string 解码后的内容 */ function getDecodedContent($conn, $email_number, $part) { $encoding = $part->encoding; $content = ''; $fetchFlags = FT_PEEK; // 只读获取,不修改邮件状态 if ($part->type === 0) { $content = imap_fetchbody($conn, $email_number, $part->partNumber, $fetchFlags); } elseif ($part->type === 1 || $part->type === 2 || $part->type === 3) { $content = imap_fetchbody($conn, $email_number, $part->partNumber, $fetchFlags); } // 根据编码类型解码内容 switch ($encoding) { case 1: // BASE64 $content = base64_decode($content); break; case 2: // QUOTED-PRINTABLE $content = quoted_printable_decode($content); break; case 3: // 8BIT case 4: // 7BIT case 5: // BINARY default: break; } return $content; } /** * 提取实际邮件内容 * * @param string $content 原始内容 * @return string 处理后的内容 */ function getActualContent($content) { $startMarker = 'base64'; $endMarker = '--b1'; $substring = $content; // 默认返回原始内容,避免匹配失败时出错 $startPos = strpos($content, $startMarker); if ($startPos !== false) { $startPos = strpos($content, PHP_EOL, $startPos) + strlen(PHP_EOL); $endPos = strpos($content, $endMarker, $startPos); if ($endPos !== false) { $substring = substr($content, $startPos, $endPos - $startPos); } } $decoded = base64_decode($substring); return $decoded !== false ? $decoded : $substring; } ?> </div> </body> </html>
关键修正说明
- 只读连接模式:在
$host中添加/readonly,彻底防止连接过程中修改邮件的已读状态 - 只读获取标记:调用
imap_fetch_overview和imap_fetchbody时添加FT_PEEK参数,确保不会误将未读邮件标记为已读 - 表格结构修复:修正原代码中错误的HTML嵌套,用
<tr>正确包裹表格行内的<td>元素 - 错误处理增强:增加对
imap_search搜索失败场景的处理,输出具体错误信息便于排查 - 函数健壮性优化:改进
getActualContent函数,避免未匹配到内容标记时出现未定义变量的错误
内容的提问来源于stack exchange,提问作者Tanzeem
相关产品推荐
相关产品推荐

