Могу ли я прочитать PST-файл Outlook (2003/2007) на C#?

Можно ли читать файл .PST с помощью C#? Я хотел бы сделать это как отдельное приложение, а не как надстройку Outlook (если это возможно).

Если вы видели другие вопросы SO, похожие на это упоминание MailNavigator, но я хочу сделать это программно на C#.

Я просмотрел пространство имен Microsoft.Office.Interop.Outlook, но, похоже, оно предназначено только для надстроек Outlook. LibPST, похоже, может читать файлы PST, но это на C (извините, Джоэл, я не изучал C до выпуска ).

Любая помощь будет принята с благодарностью, спасибо!

РЕДАКТИРОВАТЬ:

Всем спасибо за отзывы! Я принял ответ Мэтью Растона как ответ, потому что он в конечном итоге привел меня к коду, который я искал. Вот простой пример того, что у меня получилось (вам нужно будет добавить ссылку на Microsoft.Office.Interop.Outlook):

using System;
using System.Collections.Generic;
using Microsoft.Office.Interop.Outlook;

namespace PSTReader {
    class Program {
        static void Main () {
            try {
                IEnumerable<MailItem> mailItems = readPst(@"C:\temp\PST\Test.pst", "Test PST");
                foreach (MailItem mailItem in mailItems) {
                    Console.WriteLine(mailItem.SenderName + " - " + mailItem.Subject);
                }
            } catch (System.Exception ex) {
                Console.WriteLine(ex.Message);
            }
            Console.ReadLine();
        }

        private static IEnumerable<MailItem> readPst(string pstFilePath, string pstName) {
            List<MailItem> mailItems = new List<MailItem>();
            Application app = new Application();
            NameSpace outlookNs = app.GetNamespace("MAPI");
            // Add PST file (Outlook Data File) to Default Profile
            outlookNs.AddStore(pstFilePath);
            MAPIFolder rootFolder = outlookNs.Stores[pstName].GetRootFolder();
            // Traverse through all folders in the PST file
            // TODO: This is not recursive, refactor
            Folders subFolders = rootFolder.Folders;
            foreach (Folder folder in subFolders) {
                Items items = folder.Items;
                foreach (object item in items) {
                    if (item is MailItem) {
                        MailItem mailItem = item as MailItem;
                        mailItems.Add(mailItem);
                    }
                }
            }
            // Remove PST file from Default Profile
            outlookNs.RemoveStore(rootFolder);
            return mailItems;
        }
    }
}

Примечание. Этот код предполагает, что Outlook установлен и уже настроен для текущего пользователя. Он использует профиль по умолчанию (вы можете изменить профиль по умолчанию, перейдя в Почту на панели управления). Одним из основных улучшений этого кода было бы создание временного профиля для использования вместо профиля по умолчанию, а затем его уничтожение после завершения.

Ответов (13)

Решение

Библиотека Outlook Interop предназначена не только для надстроек. Например, его можно использовать для написания консольного приложения, которое просто считывает все ваши контакты Outlook. Я почти уверен, что стандартная библиотека Microsoft Outlook Interop позволит вам читать почту - хотя она, вероятно, вызовет запрос безопасности в Outlook, который пользователю придется щелкнуть.

РЕДАКТИРОВАТЬ : Фактическая реализация чтения почты с помощью Outlook Interop зависит от того, что означает ваше определение «автономный». Для работы библиотеки Outlook Interop на клиентском компьютере должен быть установлен Outlook.

// Dumps all email in Outlook to console window.
// Prompts user with warning that an application is attempting to read Outlook data.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Outlook = Microsoft.Office.Interop.Outlook;

namespace OutlookEmail
{
class Program
{
    static void Main(string[] args)
    {
        Outlook.Application app = new Outlook.Application();
        Outlook.NameSpace outlookNs = app.GetNamespace("MAPI");
        Outlook.MAPIFolder emailFolder = outlookNs.GetDefaultFolder(Microsoft.Office.Interop.Outlook.OlDefaultFolders.olFolderInbox);

        foreach (Outlook.MailItem item in emailFolder.Items)
        {
            Console.WriteLine(item.SenderEmailAddress + " " + item.Subject + "\n" + item.Body);
        }
        Console.ReadKey();
    }
}
}

Попробуйте Pstxy .

Он предоставляет .Net API для чтения файлов Outlook PST и OST без необходимости установки Outlook.

У него есть бесплатная версия для извлечения содержимого почты (текст, html и rtf). Версия plus также поддерживает вложения.

Действительно полезный код. Если у вас есть pst и вы храните свои сообщения в его корне (без какого-либо каталога), вы можете использовать следующее в методе readPst:

 MAPIFolder rootFolder = outlookNs.Stores[pstName].GetRootFolder();
 Items items = rootFolder.Items;
 foreach (object item in items)
 {
      if (item is MailItem)
      {
           MailItem mailItem = item as MailItem;
           mailItems.Add(mailItem);
      }
 }

MAPI API - это то, что вы ищете. К сожалению, он недоступен в .Net, поэтому я боюсь, что вам придется прибегнуть к вызову неуправляемого кода.

Быстрый гугл обнаруживает несколько доступных оболочек, может быть, они вам подходят?

Это также может быть полезно: http://www.wischik.com/lu/programmer/mapi_utils.html

Этот соединитель .NET для Outlook может помочь вам начать работу.

Да, вы можете использовать MS Access, а затем либо импортировать свой pst-контент, либо просто связать его (медленно!).

Как уже упоминалось в одном из ваших связанных вопросов SO, я также рекомендую использовать библиотеку Redemption . Я использую его в коммерческом приложении для обработки писем Outlook и выполнения с ними различных задач. Он работает безупречно и предотвращает появление надоедливых предупреждений системы безопасности. Это означало бы использование COM-взаимодействия, но это не должно быть проблемой.

В этом пакете есть библиотека под названием RDO, которая заменяет CDO 1.21 и позволяет вам напрямую обращаться к файлам PST. Тогда это так же просто, как написать (код VB6):

set Session = CreateObject("Redemption.RDOSession")
'open or create a PST store
set Store = Session.LogonPstStore("c:\temp\test.pst")
set Inbox = Store.GetDefaultFolder(6) 'olFolderInbox
MsgBox Inbox.Items.Count

Я прошел и сделал рефакторинг для вложенных папок

    private static IEnumerable<MailItem> readPst(string pstFilePath, string pstName)
    {
        List<MailItem> mailItems = new List<MailItem>();
        Microsoft.Office.Interop.Outlook.Application app = new Microsoft.Office.Interop.Outlook.Application();
        NameSpace outlookNs = app.GetNamespace("MAPI");

        // Add PST file (Outlook Data File) to Default Profile
        outlookNs.AddStore(pstFilePath);

        string storeInfo = null;

        foreach (Store store in outlookNs.Stores)
        {
            storeInfo = store.DisplayName;
            storeInfo = store.FilePath;
            storeInfo = store.StoreID;
        }

        MAPIFolder rootFolder = outlookNs.Stores[pstName].GetRootFolder();

        // Traverse through all folders in the PST file
        Folders subFolders = rootFolder.Folders;

        foreach (Folder folder in subFolders)
        {
            ExtractItems(mailItems, folder);
        }
        // Remove PST file from Default Profile
        outlookNs.RemoveStore(rootFolder);
        return mailItems;
    }

    private static void ExtractItems(List<MailItem> mailItems, Folder folder)
    {
        Items items = folder.Items;

        int itemcount = items.Count;

        foreach (object item in items)
        {
            if (item is MailItem)
            {
                MailItem mailItem = item as MailItem;
                mailItems.Add(mailItem);
            }
        }

        foreach (Folder subfolder in folder.Folders)
        {
            ExtractItems(mailItems, subfolder);
        }
    }

Мы собираемся использовать это, чтобы предоставить решение, которое не зависит от перспектив.

http://www.independentsoft.de/pst/index.html

Это очень дорого, но мы надеемся, что это сократит время разработки и повысит качество.

Для тех, кто упомянул, что не видит коллекцию Stores:

Коллекция магазинов была добавлена ​​в Outlook 2007. Таким образом, если вы используете библиотеку взаимодействия, созданную из более ранней версии (в попытке не зависеть от версии - это очень распространено), то вы не увидите хранилища коллекция.

Единственный способ получить магазины - это выполнить одно из следующих действий:

  • Используйте библиотеку взаимодействия для Outlook 2007 (это означает, что ваш код не будет работать с более ранними версиями Outlook).
  • Перечислить все папки верхнего уровня с помощью объектной модели Outlook, извлечь StoreID каждой папки, а затем использовать интерфейсы CDO или MAPI для получения дополнительных сведений о каждом хранилище.
  • Перечислите коллекцию InfoStores объекта сеанса CDO, а затем используйте коллекцию fields объекта InfoStore, чтобы получить дополнительную информацию о каждом магазине.
  • Или (самый сложный способ) использовать расширенный вызов MAPI (в C++): IMAPISession :: GetMsgStoresTable.

Да, с помощью Independencentsoft PST .NET можно читать / экспортировать защищенный паролем и зашифрованный файл .pst.

Я нашел некоторые ресурсы непосредственно от Microsoft, которые могут быть полезны для выполнения этой задачи. Поиск по MSDN показывает следующее.

Обратите внимание, что когда вы добавляете ссылку на Microsoft.Office.Interop.Outlook, документация требует, чтобы вы делали это через вкладку .NET, а не вкладку COM.

Вы можете использовать pstsdk.net: порт .NET библиотеки SDK формата файлов PST с открытым исходным кодом для чтения файла PST без установленного Outlook.