我可以在C#中读取Outlook(2003/2007)PST文件吗?


70

是否可以使用C#读取.PST文件?我想作为一个独立的应用程序,而不是作为Outlook插件(如果可能的话)来执行此操作。

如果看到其他 类似于此的SO 问题 ,请提及MailNavigator,但我希望以C#方式进行编程。

我查看了Microsoft.Office.Interop.Outlook命名空间,但这似乎仅用于Outlook加载项。LibPST似乎能够读取PST文件,但这是用C语言编写的(对不起,乔尔,我毕业之前没有学习C语言)。

任何帮助将不胜感激,谢谢!

编辑:

谢谢大家的答复!我接受了Matthew Ruston的回答作为答案,因为它最终使我明白了我要寻找的代码。这是我工作的一个简单示例(您将需要添加对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,并且已经为当前用户配置了Outlook。它使用默认配置文件(您可以通过控制面板中的“邮件”来编辑默认配置文件)。此代码的一个主要改进是创建一个临时配置文件以代替Default使用,然后在完成后销毁它。


我不知道Outlook API中甚至还存在AddStores和Stores列表。好帖子!
马修·鲁斯顿

我想念什么吗?为什么我不能访问OutlookNS的“商店”集合?这不是智识上的。
Mike Cole

您是否包括“使用Microsoft.Office.Interop.Outlook;” 在您的代码中?
安迪2009年

我做到了,我可以看到其他所有内容。我只是看不到Outlook名称空间的stores集合。我只是想到了什么...您引用了哪个版本的Microsoft.Office.Interop.Outlook?我使用的11
迈克·科尔

您也可以尝试使用Aspose.Network for .NET从Outlook PST文件读取和提取msg文件。请访问http://www.aspose.com/documentation/.net-components/aspose.network-for-.net/read-outlook-pst-file-and-get-folders-and-subfolders-information.html,更多信息。
萨奇布·拉扎克

Answers:


29

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

可以安全地假定将在计算机上安装Outlook,但是,我希望不必打开Outlook即可从PST文件中进行读取。
安迪

它不需要打开。interop库仅在后台打开它,并在完成后关闭它。
马修·鲁斯顿

啊,好的,听起来不错。我看到了一些有关如何使用它读取Contacts之类的示例,但我只想读取PST中的消息,而不是Exchange服务器之外的Contacts。您是否知道或有示例?
安迪

4
在过去的10分钟里,我的帖子中都有一个代码示例。这足以作为起点吗?
马修·鲁斯顿

感谢您的代码示例。看起来它是从邮箱中读取的,而不是PST文件,但是我将看到可以调整的内容以读取PST文件。我会尽快发布更新。
安迪

6

我经历了并为子文件夹进行了重构

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

什么是pstName?您已经在其中传递了pstFilePath,为什么需要pstName?
HoKy22

6

正如您在链接的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


3

尝试Pstxy

它提供.Net API来读取Outlook PST和OST文件,无需安装Outlook。

它有一个免费版本来提取邮件内容(文本,html和rtf)。加号版本也支持附件。


这是如此有希望。正如我刚刚尝试过的那样,它可以在dotnetcore中使用。可悲的是,像所有其他图书馆解决方案一样,它不支持最新的数据库格式
星期六

2
@sehe不确定是否仍然有用,请尝试使用Pstxy(以前是NetPstExtractor),它对最新格式有更好的支持。
neolei

酷@neolel我想这样总是会说相关的。感谢您保持最新答案
sehe

2

对于那些提到他们看不到“商店”集合的人:

在Outlook 2007中添加了Stores集合。因此,如果您使用的是从早期版本创建的互操作库(试图独立于版本-这很常见),那么这就是为什么您看不到Stores的原因采集。

获得商店的唯一选择是执行以下任一操作:

  • 对Outlook 2007使用互操作库(这意味着您的代码不适用于早期版本的Outlook)。
  • 使用Outlook对象模型枚举所有顶级文件夹,提取每个文件夹的StoreID,然后使用CDO或MAPI接口获取有关每个商店的更多信息。
  • 枚举CDO会话对象的InfoStores集合,然后使用InfoStore对象的字段集合以获取有关每个存储的更多信息。
  • 或者(最困难的方式)使用扩展的MAPI调用(在C ++中):IMAPISession :: GetMsgStoresTable。





0

是的,使用Independentsoft PST .NET可以读取/导出受密码保护和加密的.pst文件。


0

真正有用的代码。如果您拥有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);
      }
 }

-1

是的,您可以使用MS Access,然后导入pst内容或仅链接它(慢!)。


抱歉,我看不到如何回答有关如何在C#中读取PST文件的问题。请进一步解释。
安迪

哦,对不起,我忘记了C#部分,但是如果您可以控制C#的访问,您仍然可以这样做。未经测试!
洛伦佐
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.