在 C# .NET 中讀取 MS Outlook PST 文件

對話線程 是對具有共同線程主題的消息的一系列回复。對話中的消息可以以多種方式顯示,例如按層次或時間順序。要顯示消息線程,電子郵件應用程序會識別消息回复。最流行的電子郵件文件格式提供此功能。 對話線索可以讓讀者快速了解對話的整體結構,突出對話的某些要點,並分析重要信息。 在這篇文章中,我們將重點介紹如何使用 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 的信息。如果您有任何問題,可以發帖到我們的論壇

也可以看看