2024 年 PHP Conference Japan

imap_thread

(PHP 4 >= 4.0.7, PHP 5, PHP 7, PHP 8)

imap_thread傳回郵件的樹狀執行緒結構

說明

imap_thread(IMAP\連線 $imap, int $flags = SE_FREE): 陣列|false

取得一個訊息的樹狀執行緒結構。

參數

imap

一個 IMAP\連線 實例。

flags

回傳值

imap_thread() 返回一個關聯式陣列,其中包含了透過 `REFERENCES` 屬性串連起來的訊息樹狀結構,或者在發生錯誤時返回 false

目前信箱中的每一個訊息都會在結果陣列中以三個項目表示

  • $thread["XX.num"] - 目前訊息編號

  • $thread["XX.next"]

  • $thread["XX.branch"]

更新日誌

版本 說明
8.1.0 imap 參數現在需要一個 IMAP\連線 實例;先前,它需要一個有效的 imap 資源

範例

範例 #1 imap_thread() 範例

<?php

// 這裡我們以 HTML 格式輸出新聞群組的執行緒

$nntp = imap_open('{news.example.com:119/nntp}some.newsgroup', '', '');
$threads = imap_thread($nntp);

foreach (
$threads as $key => $val) {
$tree = explode('.', $key);
if (
$tree[1] == 'num') {
$header = imap_headerinfo($nntp, $val);
echo
"<ul>\n\t<li>" . $header->fromaddress . "\n";
} elseif (
$tree[1] == 'branch') {
echo
"\t</li>\n</ul>\n";
}
}

imap_close($nntp);

?>

新增註記

使用者貢獻的註記 2 則註記

cblanquera at gmail dot com
13 年前
imap_thread() 會傳回郵件主題,但僅限於您在 imap_open() 中定義的目前開啟的信箱。這對於獲取完整主題(例如從「已傳送郵件」和「收件匣」中獲取,這花了我一天時間才弄清楚)來說並不好用。

如果您比較 Outlook 和 gmail.com 上的主題,您會發現 Outlook 是根據主旨標題來判斷主題,而不是實際的父>子關係。

然而,Gmail 似乎正確地取得了主題,但沒有將您使用其網頁介面傳送的郵件包含在 {imap.google.com:993/imap/ssl}已傳送郵件中。這表示使用 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', 'youremail@gmail.com', 'yourpassword');
$subject = 'Item b';
$threads = array();

//remove re: and fwd:
$subject = trim(preg_replace("/Re\:|re\:|RE\:|Fwd\:|fwd\:|FWD\:/i", '', $subject));

//search for subject in current mailbox
$results = imap_search($imap, 'SUBJECT "'.$subject.'"', SE_UID);

//because results can be false
if(is_array($results)) {
//now get all the emails details that were found
$emails = imap_fetch_overview($imap, implode(',', $results), FT_UID);

//foreach email
foreach ($emails as $email) {
//add to threads
//we date date as the key because later we will sort it
$threads[strtotime($email->date)] = $email;
}
}

//now reopen sent messages
imap_reopen($imap, '{imap.gmail.com:993/imap/ssl}Sent Messages');

//and do the same thing

//search for subject in current mailbox
$results = imap_search($imap, 'SUBJECT "'.$subject.'"', SE_UID);

//because results can be false
if(is_array($results)) {
//now get all the emails details that were found
$emails = imap_fetch_overview($imap, implode(',', $results), FT_UID);

//foreach email
foreach ($emails as $email) {
//add to threads
//we date date as the key because later we will sort it
$threads[strtotime($email->date)] = $email;
}
}

//sort keys so we get threads in chronological order
ksort($threads);

echo
'<pre>'.print_r($threads, true).'</pre>';
exit;
?>

因此,如果您要有效地使用 imap_thread(),這可能是我能想到的最佳方法。

<?php
$imap
= imap_open('{imap.gmail.com:993/imap/ssl}INBOX', 'youremail@gmail.com', 'password');
$threads = $rootValues = array();

$thread = imap_thread($imap);
$root = 0;

//first we find the root (or parent) value for each email in the thread
//we ignore emails that have no root value except those that are infact
//the root of a thread

//we want to gather the message IDs in a way where we can get the details of
//all emails on one call rather than individual calls ( for performance )

//foreach thread
foreach ($thread as $i => $messageId) {
//get sequence and type
list($sequence, $type) = explode('.', $i);

//if type is not num or messageId is 0 or (start of a new thread and no next) or is already set
if($type != 'num' || $messageId == 0
|| ($root == 0 && $thread[$sequence.'.next'] == 0)
|| isset(
$rootValues[$messageId])) {
//ignore it
continue;
}

//if this is the start of a new thread
if($root == 0) {
//set root
$root = $messageId;
}

//at this point this will be part of a thread
//let's remember the root for this email
$rootValues[$messageId] = $root;

//if there is no next
if($thread[$sequence.'.next'] == 0) {
//reset root
$root = 0;
}
}

//now get all the emails details in rootValues in one call
//because one call for 1000 rows to a server is better
//than calling the server 1000 times
$emails = imap_fetch_overview($imap, implode(',', array_keys($rootValues)));

//foreach email
foreach ($emails as $email) {
//get root
$root = $rootValues[$email->msgno];

//add to threads
$threads[$root][] = $email;
}

//there is no need to sort, the threads will automagically in chronological order
echo '<pre>'.print_r($threads, true).'</pre>';
imap_close($imap);
exit;
?>
whamill at google mail
14 年前
我想其他人可能會受益於對結果陣列的解釋,我的理解是

鍵值:本質上是一個節點 ID
Num:郵件 ID(其中 0 表示對話的開始)
Next:第一個子節點的節點 ID(其中 0 表示沒有子節點)
Branch:下一個兄弟節點的節點 ID(其中 0 表示沒有兄弟節點)
To Top