【问题标题】:Can I read an Outlook (2003/2007) PST file in C#?我可以在 C# 中读取 Outlook (2003/2007) PST 文件吗?
【发布时间】:2012-06-01 19:50:03
【问题描述】:

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

如果看到 other SO questions similar 提到 MailNavigator 但我希望在 C# 中以编程方式执行此操作。

我查看了 Microsoft.Office.Interop.Outlook 命名空间,但这似乎仅适用于 Outlook 插件。 LibPST 似乎能够读取 PST 文件,但这是用 C 语言编写的(抱歉 Joel,我没有 learn C before graduating)。

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

编辑:

感谢大家的回复!我接受了 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。它使用默认配置文件(您可以通过转到控制面板中的邮件来编辑默认配置文件)。对这段代码的一个主要改进是创建一个临时配置文件来代替默认配置文件,然后在完成后将其销毁。

【问题讨论】:

  • 我不知道 AddStores 和 Stores 列表甚至存在于 Outlook API 中。好帖子!
  • 我错过了什么吗?为什么我无法访问 OutlookNS 的 Stores 集合?它不是智能感知的。
  • 您是否包括了“使用 Microsoft.Office.Interop.Outlook;”在你的代码中?
  • 我做到了,我可以看到其他所有内容。我只是看不到 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了解更多信息。

标签: c# outlook outlook-2007 outlook-2003 pst


【解决方案1】:

Outlook 互操作库不仅适用于插件。例如,它可以用来编写一个控制台应用程序,它只读取你所有的 Outlook 联系人。我很确定标准的 Microsoft Outlook 互操作库可以让您阅读邮件 - 尽管它可能会在 Outlook 中引发用户必须点击的安全提示。

编辑:实际上使用 Outlook 互操作实现邮件阅读取决于您对“独立”的定义是什么意思。 Outlook 互操作库需要在客户端计算机上安装 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 文件。
  • 不需要打开。互操作库只是在后台打开它,完成后将其关闭。
  • 啊,好吧,听起来不错。我看到了一些关于如何使用它来阅读联系人等的示例,但我只是对阅读 PST 中的消息感兴趣,而不是从 Exchange 服务器上阅读联系人。你知道,或者有一个例子吗?
  • 过去 10 分钟我的帖子中有一个代码示例。这是否足以作为一个起点?
  • 感谢代码示例。看起来它是从邮箱而不是 PST 文件读取的,但我会看看我可以调整什么来读取 PST 文件。我会尽快发布更新。
【解决方案2】:

我完成了子文件夹的重构

    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?
【解决方案3】:

正如您在其中一个链接的 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

【讨论】:

    【解决方案4】:

    您可以使用pstsdk.net: .NET port of PST File Format SDK 开源库来读取pst 文件无需安装Outlook。

    【讨论】:

    • 该页面不提供下载!
    • 它是一个包装器,而不是一个端口(这很重要,因为它的便携性较差)。
    【解决方案5】:

    试试Pstxy

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

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

    【讨论】:

    • 这很有希望。正如我刚刚尝试过的那样,它在 dotnetcore 中工作。遗憾的是,与所有其他库解决方案一样,它不支持最新的数据库格式
    • @sehe 不确定它是否仍然相关,尝试 Pstxy(以前的 NetPstExtractor),它对最新格式的支持更好。
    • 酷@neolel 我想这样它总是会说相关的。感谢您及时更新答案
    【解决方案6】:

    对于那些提到他们没有看到商店系列的人:

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

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

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

    【讨论】:

      【解决方案7】:

      我们将使用它来提供不依赖 Outlook 的解决方案。

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

      它非常昂贵,但我们希望这样可以缩短开发时间并提高质量。

      【讨论】:

      • +1 这个建议(这是我使用的)。技术支持也反应迅速。
      【解决方案8】:

      我直接从 Microsoft 找到了一些资源,这些资源可能有助于完成这项任务。 search on MSDN 揭示了以下内容。

      请注意,当您添加对 Microsoft.Office.Interop.Outlook 的引用时,the documentation 坚持要求您通过 .NET 选项卡而不是 COM 选项卡执行此操作。

      【讨论】:

        【解决方案9】:

        MAPI API 正是您所寻找的。不幸的是,它在 .Net 中不可用,所以恐怕您将不得不求助于调用非托管代码。

        快速的谷歌显示几个可用的包装器,也许它们对你有用?

        这也可能有帮助:http://www.wischik.com/lu/programmer/mapi_utils.html

        【讨论】:

          【解决方案10】:

          This Outlook 的 .NET 连接器可能会帮助您入门。

          【讨论】:

            【解决方案11】:

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

            【讨论】:

              【解决方案12】:

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

              【讨论】:

                【解决方案13】:

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

                【讨论】:

                • 对不起,我不明白这如何回答我关于如何在 C# 中读取 PST 文件的问题。请进一步解释。
                • 哦,是的,对不起,我忘记了 C# 部分,但如果你可以从 C# 控制 Access,你仍然可以这样做。未经测试!
                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2015-08-09
                • 1970-01-01
                • 2017-02-17
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多