76

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).

If have seen other SO questions similar to this mention MailNavigator but I am looking to do this programmatically in C#.

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

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):

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.

Community
  • 1
  • 1
Andy May
  • 4,030
  • 5
  • 34
  • 33
  • I had no idea that the AddStores and Stores list even existed in the Outlook API. Good post! – Matthew Ruston Feb 24 '09 at 14:38
  • Am I missing something? Why can't I access the Stores collection of the outlookNS? It's not in intellisense. – Mike Cole Sep 02 '09 at 19:05
  • Did you include 'using Microsoft.Office.Interop.Outlook;' in your code? – Andy May Sep 03 '09 at 14:06
  • I did, and I can see everything else. I just can't see the stores collection of the outlook namespace. I just thought of something... what version of Microsoft.Office.Interop.Outlook do you have referenced? I am using 11. – Mike Cole Sep 03 '09 at 14:50
  • This is a really legit question. I know this is a really old post, but why is it closed as not constructive? – TtT23 Dec 07 '12 at 05:22
  • Great question @l46kok ... You could vote to reopen it if you want. – Andy May Dec 07 '12 at 18:38
  • Stuck at Outlook MAPI - You cannot close the mailbox that contains your calendar, contacts, and inbox. ?? error!! do i have to edit->delete the root folder. – Aashu Aug 22 '13 at 07:47
  • What is pstName? You already passes the pstFilePath in it, why do you need pstName? – HoKy22 Jul 16 '14 at 17:50
  • You may also try Aspose.Network for .NET to read and extract msg files from Outlook PST file. Please visit [http://www.aspose.com/documentation/.net-components/aspose.network-for-.net/read-outlook-pst-file-and-get-folders-and-subfolders-information.html](http://www.aspose.com/documentation/.net-components/aspose.network-for-.net/read-outlook-pst-file-and-get-folders-and-subfolders-information.html) for more information. – Saqib Razzaq Jun 13 '10 at 18:48

13 Answers13

30

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.

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.

// 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();
    }
}
}
Matthew Ruston
  • 4,282
  • 7
  • 38
  • 47
  • It is safe to assume that Outlook will be installed on the machine, however, I would prefer that it is not necessary to have Outlook open to read from the PST file. – Andy May Feb 23 '09 at 15:20
  • It doesn't need to be open. The interop lib just opens it in the background and closes it when your done. – Matthew Ruston Feb 23 '09 at 15:23
  • Ahhh, ok, that sounds good. I see some examples for how to use this to read Contacts and such, but I'm just interested in reading messages in a PST, not Contacts off of an Exchange server. Do you know, or have an example, on this? – Andy May Feb 23 '09 at 15:40
  • 4
    I've had a code example in my post for the past 10 minutes. Does that suffice as a starting point? – Matthew Ruston Feb 23 '09 at 15:46
  • Thanks for the code example. That looks like it is reading from the Mailbox and not a PST file, but I'll see what I can tweak to read a PST file. I'll post an update soon. – Andy May Feb 23 '09 at 16:07
  • That wont work. The mailbox is WITHIN the PST file. PST files represent an entire user account within Outlook. The code above goes into the default user profile (PST file) in Outlook and reads their mail. – Matthew Ruston Feb 23 '09 at 16:13
  • The above code works. It is already, technically, reading from a PST file. I think you need to do some more background research on the Outlook Interop lib. – Matthew Ruston Feb 23 '09 at 16:41
  • Very true. Your answer provided the most help and ultimately led me to the solution. I will edit my original post to include my solution. Thank you for your help! – Andy May Feb 24 '09 at 13:21
8

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);
        }
    }
Tom Kidd
  • 12,830
  • 19
  • 89
  • 128
6

As already mentioned in one of your linked SO questions, I'd also recommend using the Redemption library. 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.

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):

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
Dmitry Streblechenko
  • 62,942
  • 4
  • 53
  • 78
MicSim
  • 26,265
  • 16
  • 90
  • 133
4

You can use pstsdk.net: .NET port of PST File Format SDK library which is open source to read pst file without Outlook installed.

Giorgi
  • 30,270
  • 13
  • 89
  • 125
3

Try Pstxy.

It provide .Net API to read Outlook PST & OST file without need for Outlook installed.

It has a free version to extract mail content (text, html & rtf). The plus version support attachments, too.

neolei
  • 1,798
  • 2
  • 18
  • 32
  • This is so promising. It works in dotnetcore, as I've just tried. Sadly, like all the other library solutions it doesn't support latest database formats – sehe Jul 21 '18 at 15:23
  • 2
    @sehe not sure if it's still relevant, try Pstxy (NetPstExtractor previously), it has better support for latest format. – neolei Mar 31 '20 at 09:02
  • Cool @neolel I guess this way it will always say relevant. Thanks for keeping the answer up to date – sehe Mar 31 '20 at 11:36
2

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

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.

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.
Ryan Farley
  • 11,315
  • 4
  • 46
  • 43
1

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

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

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

Chris Barry
  • 4,564
  • 7
  • 54
  • 89
1

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

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

HappyNomad
  • 4,458
  • 4
  • 36
  • 55
0

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

AlanSB
  • 9
  • 1
0

Really usefull code. If you have pst and store your messages in its root (without any directory), then you can use the following in method 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);
      }
 }
0

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.

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

Gerrie Schenck
  • 22,148
  • 20
  • 68
  • 95
0

This .NET connector for Outlook might get you started.

Chris Ballance
  • 33,810
  • 26
  • 104
  • 151
-1

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

Lorenzo
  • 4,558
  • 11
  • 44
  • 54
  • Sorry, I don't see how this answers my question about how to read a PST file in C#. Please explain further. – Andy May Feb 23 '09 at 15:25
  • Oh yeah sorry, i forgot the C# part, but if you maybe can control Access from C# you could still go that way. Untested! – Lorenzo Feb 23 '09 at 15:35