imap_thread() 返回线程,但仅限于您在 imap_open() 中定义的当前打开的邮箱。这对例如获取完整线程(来自“已发送邮件”和“收件箱”[我花了一天才弄明白])没有用。
如果您将 Outlook 和 gmail.com 上的线程进行比较,您会发现 Outlook 通过主题标题来确定线程,而不是实际的父 > 子关系。
然而,Gmail 似乎正确地获得了线程,但不会在 {imap.google.com:993/imap/ssl}Sent Messages 中包含您使用其 Web 界面发送的邮件。这意味着使用 php imap 的线程对于 Gmail 来说并不完美。
如果您使用 Outlook(或任何邮件客户端)发送邮件,gmail.com 确实会将其放入其“已发送邮件”中。
总而言之,PHP imap 的线程并不完美。但我更责怪 imap 规范(亲爱的 IMAP 人员,请添加更好的 uid 和父 id。谢谢 Chris),而不是 PHP
因此,我在下面创建了 Outlook 线程方法(比较主题)
<?php
$imap = imap_open('{imap.gmail.com:993/imap/ssl}INBOX', '[email protected]', 'yourpassword');
$subject = 'Item b';
$threads = array();
// 移除 re: 和 fwd:
$subject = trim(preg_replace("/Re\:|re\:|RE\:|Fwd\:|fwd\:|FWD\:/i", '', $subject));
// 在当前邮箱中搜索主题
$results = imap_search($imap, 'SUBJECT "'.$subject.'"', SE_UID);
// 因为结果可能是 false
if(is_array($results)) {
// 现在获取所有找到的邮件详细信息
$emails = imap_fetch_overview($imap, implode(',', $results), FT_UID);
// 遍历每封邮件
foreach ($emails as $email) {
// 添加到线程
// 我们将日期作为键,因为稍后我们将对其进行排序
$threads[strtotime($email->date)] = $email;
}
}
// 现在重新打开已发送邮件
imap_reopen($imap, '{imap.gmail.com:993/imap/ssl}Sent Messages');
// 并执行相同的操作
// 在当前邮箱中搜索主题
$results = imap_search($imap, 'SUBJECT "'.$subject.'"', SE_UID);
// 因为结果可能是 false
if(is_array($results)) {
// 现在获取所有找到的邮件详细信息
$emails = imap_fetch_overview($imap, implode(',', $results), FT_UID);
// 遍历每封邮件
foreach ($emails as $email) {
// 添加到线程
// 我们将日期作为键,因为稍后我们将对其进行排序
$threads[strtotime($email->date)] = $email;
}
}
// 按时间顺序对键进行排序,以便我们按时间顺序获取线程
ksort($threads);
echo '<pre>'.print_r($threads, true).'</pre>';
exit;
?>
因此,如果您要将 imap_thread() 用于有用的用途。这可能是我能想到的最优方法
<?php
$imap = imap_open('{imap.gmail.com:993/imap/ssl}INBOX', '[email protected]', 'password');
$threads = $rootValues = array();
$thread = imap_thread($imap);
$root = 0;
// 首先我们找到每个邮件在邮件线程中的根(或父)值
// 我们忽略没有根值的邮件,除了那些实际上是
// 线程的根
// 我们希望以一种方式收集邮件 ID,以便我们可以获得详细信息
// 所有邮件在一个调用中而不是单独调用(为了性能)
// 对于每个线程
foreach ($thread as $i => $messageId) {
// 获取序列和类型
list($sequence, $type) = explode('.', $i);
// 如果类型不是 num 或 messageId 为 0 或(新线程的开始且没有下一个)或已设置
if($type != 'num' || $messageId == 0
|| ($root == 0 && $thread[$sequence.'.next'] == 0)
|| isset($rootValues[$messageId])) {
// 忽略它
continue;
}
// 如果这是新线程的开始
if($root == 0) {
// 设置根
$root = $messageId;
}
// 在这一点上,这将成为线程的一部分
// 让我们记住这封邮件的根
$rootValues[$messageId] = $root;
// 如果没有下一个
if($thread[$sequence.'.next'] == 0) {
// 重置根
$root = 0;
}
}
// 现在在一次调用中获取 rootValues 中所有邮件的详细信息
// 因为对服务器的 1000 行进行一次调用比调用服务器 1000 次更好
$emails = imap_fetch_overview($imap, implode(',', array_keys($rootValues)));
// 对于每个邮件
foreach ($emails as $email) {
// 获取根
$root = $rootValues[$email->msgno];
// 添加到线程
$threads[$root][] = $email;
}
// 不需要排序,线程将自动按时间顺序排列
echo '<pre>'.print_r($threads, true).'</pre>';
imap_close($imap);
exit;
?>