對話線程 是對具有共同線程主題的消息的一系列回复。對話中的消息可以以多種方式顯示,例如按層次或時間順序。要顯示消息線程,電子郵件應用程序會識別消息回复。最流行的電子郵件文件格式提供此功能。 對話線索可以讓讀者快速了解對話的整體結構,突出對話的某些要點,並分析重要信息。 在這篇文章中,我們將重點介紹如何使用 Aspose.Email 的 PST/MAPI 功能來按會話查找和分組郵件。為此,我們將實施一個示例代碼,該代碼將遍歷給定文件夾中的消息,按對話對它們進行分組,然後將每個對話保存到單獨的磁盤目錄中。
用於支持對話線程的 MAPI 屬性
由於 pst 中的消息存儲為一組 MAPI 屬性,我們需要定義與收集消息回復相關聯的 MAPI 屬性。 Microsoft 文檔部分 中對此進行了描述。 可以看出,PidTagConversationIndex 屬性允許準確確定一條消息是否與某個對話相關聯。該屬性還指示對話線程中的相對消息位置。 訪問頁面 了解有關“PidTagConversationIndex”屬性的更多信息。標頭是“PidTagConversationIndex”屬性值的前 22 個字節。判斷消息是否屬於某個會話線程的數據部分。
用於讀取 Outlook PST 文件的 C# .NET API
要讀取 PST 文件,我們將使用 Aspose.Email for .NET。這是一個很棒的庫,可以使用 .NET 實現電子郵件處理應用程序。使用該庫,您可以輕鬆處理許多不同的電子郵件文件格式。您可以通過 NuGet 或 下載 它的 DLL 安裝 Aspose.Email for .NET。
PM> Install-Package Aspose.Email
按對話線程對 PST 中的消息進行分組
要按對話對 PST 中的消息進行分組,我們需要以下內容:
- 首先,創建一個“ConversationThread”類。它是一個容器,用於對對話中的消息進行分組。
- 然後,創建一種按對話搜索和分組消息的方法。
- 最後,創建一個將對話線程保存到單獨目錄的方法。
創建一個 ConversationThread 類
它將具有以下屬性。
Id
:會話索引標頭的字符串表示形式(22 字節)。Messages
:對話線程中的消息 ID 列表。
///<summary>
/// 表示對話線程中的消息。
///</summary>
public class ConversationThread
{
private string id;
private List<string> messages;
///<summary>
/// 初始化一個新的實例<see cref="ConversationThread"/>班級。
///</summary>
///<param name="id">會話索引標頭的字符串表示形式。</param>
public MessageThread(string id)
{
this.id = id;
this.messages = new List<string>();
}
///<summary>
/// 獲取或設置會話索引標頭的 HEX 字符串表示形式(22 字節)。
///</summary>
public string Id { get => id; set => id = value; }
///<summary>
/// 獲取對話線程中的消息 ID 列表。
///</summary>
public List<string> Messages { get => messages; }
}
創建一種通過對話搜索和分組消息的方法
創建 ConversationThread 類後,我們可以專注於編寫執行以下操作的方法:
- 瀏覽文件夾中的所有郵件。出於性能原因,我們將僅使用 EnumerateMessagesEntryId 方法讀取消息標識符。
- 對於每條消息,我們將使用 ExtractProperty 方法提取“PidTagConversationIndex”屬性。
- 具有相同前 22 個字節的
PidTagConversationIndex
屬性值的消息屬於同一個會話。我們將把消息 Id 添加到由相應ConversationThread
類實例的Messages
屬性表示的列表中。 - 返回“ConversationThread”實例的列表。
using Aspose.Email.Mapi;
using Aspose.Email.Storage.Pst;
public List<ConversationThread> GroupMessagesByThread(PersonalStorage pst, FolderInfo folder)
{
// 結果
var list = new List<ConversationThread>();
foreach (var entryId in folder.EnumerateMessagesEntryId())
{
// 提取 PidTagConversationIndex 屬性及其標頭值(22 字節)。
var convIndexTag = KnownPropertyList.ConversationIndex.Tag;
var convIndexProperty = pst.ExtractProperty(Convert.FromBase64String(entryId), convIndexTag);
var convIndexHeader = (convIndexProperty != null && convIndexProperty.Data != null) ? convIndexProperty.Data.Take(22).ToArray() : null;
var convIndexHeaderString = convIndexHeader != null ?
BitConverter.ToString(convIndexHeader).Replace('-', '') : null;
if (convIndexHeaderString != null)
{
var convThread = list.Find(x => x.Id == convIndexHeaderString);
if (convThread == null)
{
convThread = new ConversationThread(convIndexHeaderString);
convThread.Messages.Add(entryId);
list.Add(convThread);
}
else
{
convThread.Messages.Add(entryId);
}
}
}
return list.Where(x => x.Messages.Count > 1).ToList();
}
創建一種將對話線程保存到單獨目錄的方法
最後,讓我們將對話保存在目錄中。
對於每個“ConversationThread”實例,執行以下操作:
- 使用線程主題的名稱創建一個單獨的目錄。
- 在
ConversationThread.Messages
屬性中枚舉標識符,使用 ExtractMessage 方法為每個標識符提取一條消息,並使用 Save 方法將消息保存在創建的目錄中。
public void SaveThreads(List<ConversationThread> list, string outDirectory)
{
var invalidChars = Path.GetInvalidFileNameChars();
foreach (var item in list)
{
string? threadDirectory = null;
var i = item.Messages.Count - 1;
foreach (var entryId in item.Messages)
{
var msg = pst.ExtractMessage(entryId);
if (threadDirectory == null)
{
var threadName = new string(msg.ConversationTopic.Where(x => !invalidChars.Contains(x)).ToArray()).Trim();
threadDirectory = Path.Combine(outDirectory, threadName);
Directory.CreateDirectory(threadDirectory);
}
msg.Save(Path.Combine(threadDirectory, $"{i--}.msg"));
}
threadDirectory = null;
}
}
獲取免費的 API 許可證
您可以使用 免費臨時許可證 不受評估限制地使用 Aspose.Email for .NET。
結論
本文介紹如何使用 Aspose.Email 在 PST 中搜索與對話相關的郵件。 通過進一步探索 PidTagConversationIndex 文檔,您還可以通過添加對話消息的層次排序等方式使實現複雜化。您可以使用 文檔 了解更多關於 Aspose.Email 的信息。如果您有任何問題,可以發帖到我們的論壇。