Читайте PST-файли MS Outlook у C# .NET

Літка бесіди — це послідовність відповідей на повідомлення зі спільною темою гілки. Повідомлення в бесіді можна відображати різними способами, наприклад в ієрархічному або хронологічному порядку. Щоб відобразити ланцюжок повідомлень, програми електронної пошти ідентифікують відповіді на повідомлення. Найпопулярніші формати файлів електронної пошти забезпечують цю функцію. Нитки розмов дозволяють читачам швидко зрозуміти загальну структуру розмови, виділити певні моменти розмов і проаналізувати важливу інформацію. У цій статті ми зосередимося на використанні функцій PST/MAPI Aspose.Email для пошуку та групування повідомлень за бесідою. Для цього ми реалізуємо зразок коду, який проходитиме повідомлення в заданій папці, групуватиме їх за бесідою, а потім зберігатиме кожну бесіду в окремому каталозі на диску.

Властивості MAPI, які використовуються для підтримки потоку розмови

Оскільки повідомлення в pst зберігаються як набір властивостей MAPI, нам потрібно визначити властивості MAPI, які пов’язані зі збором відповідей на повідомлення. Це описано в розділі Microsoft Docs. Як бачимо, властивість PidTagConversationIndex дозволяє точно визначити, чи пов’язане повідомлення з певною бесідою чи ні. Властивість також вказує відносну позицію повідомлення в ланцюжку бесіди. Відвідайте сторінку, щоб дізнатися більше про властивість PidTagConversationIndex. Заголовок — це перші 22 байти значення властивості PidTagConversationIndex. Це частина даних, яка дає змогу визначити, чи належить повідомлення певній темі бесіди.

C# .NET API для читання PST-файлів Outlook

Щоб читати файли PST, ми будемо використовувати Aspose.Email for .NET. Це дивовижна бібліотека для реалізації програм обробки електронної пошти за допомогою .NET. Використовуючи бібліотеку, ви можете легко працювати з багатьма різними форматами файлів електронної пошти. Ви можете встановити Aspose.Email for .NET через NuGet або завантажити його DLL.

PM> Install-Package Aspose.Email

Групуйте повідомлення в PST за ланцюжком розмов

Щоб згрупувати повідомлення в PST за розмовами, нам потрібно:

  • По-перше, створіть клас ConversationThread. Це контейнер для групування повідомлень у розмові.
  • Потім створіть метод для пошуку та групування повідомлень за бесідою.
  • Нарешті, створіть метод для збереження ланцюжка розмов в окремому каталозі.

Створіть клас ConversationThread

Він матиме такі властивості.

  • Id: рядкове представлення заголовка індексу розмови (22 байти).
  • Повідомлення: список ідентифікаторів повідомлень, які є в ланцюжку бесіди.
///<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>
    /// Отримує список ідентифікаторів повідомлень, які знаходяться в ланцюжку бесіди.
    ///</summary>
    public List<string> Messages { get => messages; }
}

Створіть метод пошуку та групування повідомлень за бесідою

Після створення класу ConversationThread ми можемо зосередитися на написанні методу, який робить наступне:

  • Перегляньте всі повідомлення в папці. З міркувань продуктивності ми читатимемо ідентифікатор повідомлення лише за допомогою методу EnumerateMessagesEntryId.
  • Для кожного повідомлення ми витягнемо властивість PidTagConversationIndex за допомогою методу ExtractProperty.
  • Повідомлення, які мають однакові перші 22 байти значення властивості PidTagConversationIndex, належать до однієї розмови. Ми додамо ідентифікатор повідомлення до списку, представленого властивістю Messages відповідного екземпляра класу ConversationThread.
  • Повертає список екземплярів 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, використовуючи документацію. Якщо у вас виникнуть запитання, ви можете опублікувати їх на нашому форумі.

Дивись також