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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/577904/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 09:01:13  来源:igfitidea点击:

Can I read an Outlook (2003/2007) PST file in C#?

c#outlookoutlook-2007outlook-2003pst

提问by Andy May

Is it possible to read a .PST file using C#? I would like to do this as a standalone application, not as an Outlook addin (if that is possible).

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

If have seen otherSOquestionssimilarto this mention MailNavigatorbut I am looking to do this programmatically in C#.

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

I have looked at the Microsoft.Office.Interop.Outlooknamespace but that appears to be just for Outlook addins. LibPSTappears to be able to read PST files, but this is in C (sorry Joel, I didn't learn C before graduating).

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

Any help would be greatly appreciated, thanks!

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

EDIT:

编辑:

Thank you all for the responses! I accepted Matthew Ruston's response as the answer because it ultimately led me to the code I was looking for. Here is a simple example of what I got to work (You will need to add a reference to Microsoft.Office.Interop.Outlook):

谢谢大家的回复!我接受了 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;
        }
    }
}

Note:This code assumes that Outlook is installed and already configured for the current user. It uses the Default Profile (you can edit the default profile by going to Mail in the Control Panel). One major improvement on this code would be to create a temporary profile to use instead of the Default, then destroy it once completed.

注意:此代码假定已为当前用户安装并配置了 Outlook。它使用默认配置文件(您可以通过转到“控制面板”中的“邮件”来编辑默认配置文件)。此代码的一项主要改进是创建一个临时配置文件来代替默认配置文件,然后在完成后销毁它。

采纳答案by Matthew Ruston

The Outlook Interop library is not just for addins. For example it could be used to write a console app that just reads all your Outlook Contacts. I am pretty sure that the standard Microsoft Outlook Interop library will let you read the mail - albeit it will probably throw a security prompt in Outlook that the user will have to click through.

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

EDITS: Actually implementing mail reading using Outlook Interop depends on what your definition of 'standalone' means. The Outlook Interop lib requires Outlook to be installed on the client machine in order to function.

编辑:实际使用 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();
    }
}
}

回答by Gerrie Schenck

The MAPI API is what you are looking for. Unfortunately it is not available in .Net so I'm afraid you will have to resort to calling unmanaged code.

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

A quick Google reveals several wrappers available, maybe they work for you?

一个快速的谷歌揭示了几个可用的包装器,也许它们适合你?

This might also be helpful: http://www.wischik.com/lu/programmer/mapi_utils.html

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

回答by Chris Ballance

This.NET connector for Outlook might get you started.

这个用于 Outlook 的 .NET 连接器可能会帮助您入门。

回答by Lorenzo

Yes you can use MS Access and then you either import your pst content or just link it (slow!).

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

回答by MicSim

As already mentioned in one of your linked SO questions, I'd also recommend using the Redemptionlibrary. I'm using it in a commercial application for processing Outlook mails and performing various tasks with them. It's working flawlessly and prevents showing up the annoying security alerts. It would mean using COM Interop, but that shouldn't be a problem.

正如您在一个链接的 SO 问题中已经提到的,我还建议使用Redemption库。我在商业应用程序中使用它来处理 Outlook 邮件并使用它们执行各种任务。它可以完美运行并防止出现烦人的安全警报。这意味着使用 COM Interop,但这应该不是问题。

There's a library in that package called RDO which is replacing the CDO 1.21, which lets you access PST files directly. Then it's as easy as writing (VB6 code):

该包中有一个名为 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

回答by Tom Kidd

I went through and did the refactoring for subfolders

我经历了对子文件夹的重构

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

回答by Chris Barry

We are going to use this, to provide a solution that doesn't rely on outlook.

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

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

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

It is very expensive, but we hope that will lower development time and increase quality.

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

回答by Ryan Farley

For those mentioning that they don't see the Stores collection:

对于那些提到他们没有看到 Stores 集合的人:

The Stores collection was added in Outlook 2007. So, if you're using an interop library created from an earlier version (in an attempt to be version independent - this is ver common) then this would be why you won't see the Stores collection.

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

Your only options to get the Stores are to do one of the following:

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

  • Use an interop library for Outlook 2007 (this means your code won't work for earlier versions of Outlook).
  • Enumerate all top level folders with Outlook object model, extract the StoreID of each folder, and then use CDO or MAPI interfaces to get more information about each store.
  • Enumerate the InfoStores collection of CDO session object, and then use the fields collection of InfoStore object in order to get more information about each store.
  • Or (the hardest way) use extended MAPI call (In C++): IMAPISession::GetMsgStoresTable.
  • 使用 Outlook 2007 的互操作库(这意味着您的代码不适用于早期版本的 Outlook)。
  • 使用 Outlook 对象模型枚举所有顶级文件夹,提取每个文件夹的 StoreID,然后使用 CDO 或 MAPI 接口获取有关每个存储的更多信息。
  • 枚举 CDO session 对象的 InfoStores 集合,然后使用 InfoStore 对象的 fields 集合来获取有关每个商店的更多信息。
  • 或者(最难的方法)使用扩展的 MAPI 调用(在 C++ 中):IMAPISession::GetMsgStoresTable。

回答by AlanSB

Yes, with Independentsoft PST .NET is possible to read/export password protected and encrypted .pst file.

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

回答by HappyNomad

I found some resources directly from Microsoft which may be helpful for completing this task. A search on MSDNreveals the following.

我直接从 Microsoft 找到了一些可能有助于完成此任务的资源。在 MSDN 上搜索揭示了以下内容。

Note that when you're adding a reference to Microsoft.Office.Interop.Outlook, the documentationinsists that you do so via the .NET tab instead of the COM tab.

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