Можно ли прочитать 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 установлен и уже настроен для текущего пользователя. Он использует профиль по умолчанию (вы можете отредактировать профиль по умолчанию, перейдя в раздел "Почта" на панели управления). Одним из основных улучшений в этом коде будет создание временного профиля для использования вместо Default, а затем его уничтожение после завершения.

13 ответов

Решение

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

РЕДАКТИРОВАТЬ: Фактически реализация чтения почты с помощью Outlook Interop зависит от того, что означает ваше определение "автономный". Для работы Outlook Interop lib требуется, чтобы на клиентском компьютере был установлен 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();
    }
}
}

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

    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);
        }
    }

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

В этом пакете есть библиотека под названием 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

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

Другое дополнительное решение: NetPstExtractor

Это API.Net для чтения файла Outlook PST без установленного Outlook.

Вы можете найти демо-версию здесь.

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

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

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

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

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

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

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

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

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

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

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

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

Действительно полезный код. Если у вас есть 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);
      }
 }

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

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

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

Другие вопросы по тегам