You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP IMAP库读取已读/未读邮件返回0结果的解决方法

解决PHP-IMAP使用SEEN/UNSEEN搜索无结果的问题

问题根源

  1. 连接邮箱时未启用/readonly模式,导致获取邮件过程中自动将未读邮件标记为已读,后续搜索UNSEEN无结果
  2. 原代码中HTML表格结构嵌套错误(用<div class="row">包裹<td>),引发页面渲染异常
  3. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 04:34:53