Pieter van der Westhuizen

Working with Outlook Accounts, Stores, Folders and Items

Any user of Microsoft Outlook will tell you that you cannot use Outlook without first setting up an account. This account can either be an Exchange server, POP or IMAP account, although Outlook can support any MAPI style account too.

So, an Outlook account is pretty easy to understand but how does it fit within an Outlook Store? In short, an Outlook account cannot really exist without an Outlook Store. The store is used to, well, store the Outlook data, this includes your folders and items (E-mails, Contacts etc.)

Outlook stores, folders and items

In this article, we’ll take a look at how you can access and use these objects in your Outlook add-ins.

Outlook Accounts

The Outlook Accounts object is a collection of Account objects and allows you to get a reference to all the accounts for a given profile, identify the type of account and use a specific account to send e-mails. There are no way to programmatically add or remove an Account using the Outlook object model.

Getting a list of accounts

You can get a reference to the Accounts collection via the NameSpace object. In the following code listing, I enumerated the accounts collection and printed the user name and e-mail associated with the account.

C# code example

Outlook.NameSpace ns = null;
    Outlook.Accounts accounts = null;
    Outlook.Account account = null;
    string accountList = string.Empty;
 
    try
    {
        ns = OutlookApp.Session;
        accounts = ns.Accounts;
        for (int i = 1; i <= accounts.Count; i++)
        {
            account = accounts[i];
            accountList += String.Format("{0} - {1}{2}", 
                account.UserName,  
                account.SmtpAddress, 
                Environment.NewLine);
            if (account != null)
                Marshal.ReleaseComObject(account);
        }
        MessageBox.Show(accountList);
    }
    finally
    {
        if (accounts != null)
            Marshal.ReleaseComObject(accounts);
        if (ns != null)
            Marshal.ReleaseComObject(ns);
    }

Notable properties

The Account object contains a number of useful properties, some of which are listed below:

Name Description
DeliveryStore Returns the default delivery Store object for the account.
AccountType Use this to establish what kind of account it is e.g. Exchange, POP3, IMAP etc.
CurrentUser This property is used to get a reference to a Recipient object that represents the current user for the account.
SmtpAddress If you only need the e-mail address of the current account, use this property.

Outlook Stores

Like the Accounts object the Stores object contains a collection that lets you enumerate the stores for a given profile.

Getting a list of stores

The Namespace object contains a reference to the Stores collection, and in the following code I enumerated the said collection, and printed the store name whether it is a .pst or .ost file:

C# code example

Outlook.NameSpace ns = null;
Outlook.Stores stores = null;
Outlook.Store store = null;
string storeList = string.Empty;
 
try
{
    ns = OutlookApp.Session;
    stores = ns.Stores;
 
    for (int i = 1; i <= stores.Count; i++)
    {
        store = stores[i];
        storeList += String.Format("{0} - {1}{2}", 
            store.DisplayName, 
            (store.IsDataFileStore ? ".pst" : ".ost"), 
            Environment.NewLine);
        if (store != null)
            Marshal.ReleaseComObject(store);
    }
    MessageBox.Show(storeList);
}
finally
{
    if (stores != null)
        Marshal.ReleaseComObject(stores);
    if (ns != null)
        Marshal.ReleaseComObject(ns);
}

Adding and removing a store

The Outlook object model provides methods to quickly and easily add or remove stores to the profile. The only Store you can add programmatically is a .pst store, as illustrated below:

C# code example

Outlook.NameSpace ns = null;
string pstPath = string.Empty;
 
try
{
    pstPath = @"C:\Temp\Backup.pst";
    ns = OutlookApp.Session;
    ns.AddStoreEx(pstPath, Outlook.OlStoreType.olStoreDefault);
}
finally
{
    if (ns != null)
        Marshal.ReleaseComObject(ns);
}

In the following example, I removed the store in which the current folder was located:

Outlook.NameSpace ns = null;
Outlook.Explorer currExplorer = null;
Outlook.MAPIFolder currFolder = null;
Outlook.Store store = null;
Outlook.MAPIFolder storeFolder = null;
 
try
{
    ns = OutlookApp.Session;
    currExplorer = OutlookApp.ActiveExplorer();
    currFolder = currExplorer.CurrentFolder;
    store = currFolder.Store;
    storeFolder = store.GetRootFolder();
 
    ns.RemoveStore(storeFolder);
}
finally
{
    if (storeFolder != null)
        Marshal.ReleaseComObject(storeFolder);
    if (store != null)
        Marshal.ReleaseComObject(store);
    if (currFolder != null)
        Marshal.ReleaseComObject(currFolder);
    if (currExplorer != null)
        Marshal.ReleaseComObject(currExplorer);
    if (ns != null)
        Marshal.ReleaseComObject(ns);
}

Notable methods

GetRootFolder

The Store object contains a number of useful methods. The first we’ll look at is the GetRootFolder method. This method, as its name suggests, returns a MAPIFolder object that contains reference to the root folder of the Store. You can then use this folder to access any child folders.

GetSearchFolders

The GetSearchFolders method returns a collection of all the search folders for a specific Store. A search folder is a folder that contains a view of all items that match a specific criteria.

GetRules

By calling the GetRules method of the Store object, you receive a collection of Rule objects for the current session. Be warned though, to call the GetRules method can take a long time on slow connections to an Exchange server!

Outlook Store events

The Store object provides two events, one to let you know when a Store object has been added and another before a Store object is removed.

The StoreAdd event occurs when you add a new store to the profile and sends a reference to the new store as a parameter:

void stores_StoreAdd(Outlook.Store Store)
{
    MessageBox.Show("You've added store called " + Store.DisplayName);
}

The BeforeStoreRemove event is fired just before a Store is removed. A parameter containing a reference to the store that is being removed is passed as well as a Boolean parameter with which you can cancel the remove action.

void stores_BeforeStoreRemove(Outlook.Store Store, ref bool Cancel)
{
    if (MessageBox.Show("You are about to remove a store called " + 
            Store.DisplayName + ". Are you sure?",
        "Confirm removal", MessageBoxButtons.YesNoCancel) != DialogResult.Yes)
    {
        Cancel = true;
    }
}

Outlook Folders

The Folders object contains a collection of Folder objects for either a Store or a Folder. Each Folder object in turn also has its own Folders property, you can use this to access the folders’ child folders.

Getting a list of folders

The following code listing illustrates how to get the root folder of a store and display all its child folders.

C# code example

Outlook.NameSpace ns = null;
Outlook.Stores stores = null;
Outlook.Store store = null;
Outlook.MAPIFolder rootFolder = null;
Outlook.Folders folders=null;
Outlook.MAPIFolder folder = null;
string folderList = string.Empty;
 
try
{
    ns = OutlookApp.Session;
    stores = ns.Stores;
    store = stores[1];
    rootFolder = store.GetRootFolder();
    folders=rootFolder.Folders;
 
    for (int i = 1; i < folders.Count; i++)
    {
        folder = folders[i];
        folderList += folder.Name + Environment.NewLine;
        if (folder != null)
            Marshal.ReleaseComObject(folder);
    }
    MessageBox.Show(folderList);
}
finally
{
    if (folders != null)
        Marshal.ReleaseComObject(folders);
    if (folders != null)
        Marshal.ReleaseComObject(folders);
    if (rootFolder != null)
        Marshal.ReleaseComObject(rootFolder);
    if (store != null)
        Marshal.ReleaseComObject(store);
    if (stores != null)
        Marshal.ReleaseComObject(stores);
    if (ns != null)
        Marshal.ReleaseComObject(ns);
}

Adding and removing a folder

To add a folder to a Folders collection you first need to get a reference to a folder, and then use the Add method on its Folders collection, as illustrated below:

C# code example

Outlook.NameSpace ns = null;
Outlook.Stores stores = null;
Outlook.Store store = null;
Outlook.MAPIFolder rootFolder = null;
Outlook.MAPIFolder folder = null;
Outlook.Folders folders = null;
 
try
{
    ns = OutlookApp.Session;
    stores = ns.Stores;
    store = stores[1];
    rootFolder = store.GetRootFolder();
    folders = rootFolder.Folders;
 
    folder = folders.Add("My New Folder", ADXOlDefaultFolders.olFolderInbox);
}
finally
{
    if (folders != null)
        Marshal.ReleaseComObject(folders);
    if (folder != null)
        Marshal.ReleaseComObject(folder);
    if (rootFolder != null)
        Marshal.ReleaseComObject(rootFolder);
    if (store != null)
        Marshal.ReleaseComObject(store);
    if (stores != null)
        Marshal.ReleaseComObject(stores);
    if (ns != null)
        Marshal.ReleaseComObject(ns);
}

To delete a folder, you can either use the Remove method on the Folder’s object, or you can obtain a reference to the folder and use its Delete method.

Outlook.Explorer currExplorer = null;
Outlook.Folder folder = null;
 
try
{
    currExplorer = OutlookApp.ActiveExplorer();
    folder = (Outlook.Folder)currExplorer.CurrentFolder;
 
    if (MessageBox.Show("Are you sure you want to delete the selected folder?",
        "Confirm deletion", MessageBoxButtons.YesNoCancel) == DialogResult.Yes)
    {
        folder.Delete();
    }
}
finally
{
    if (folder != null)
        Marshal.ReleaseComObject(folder);
    if (currExplorer != null)
        Marshal.ReleaseComObject(currExplorer);
}

Folders events

The Folder object has three events, FolderAdd which occurs when a folders is added to the Folders collection. The folder that is added is passed into the event as a parameter.

void folders_FolderChange(Outlook.MAPIFolder Folder)
{
    MessageBox.Show(String.Format("A new folder called {0} is being added.", Folder.Name));
}

FolderRemove is the opposite of the FolderAdd event and occurs when a folder is removed from the Folders collection. Unfortunately, the event does not indicate which folder is removed.

void folders_FolderRemove()
{
    MessageBox.Show("A folder was removed");
}

Lastly FolderChange can be used to determine when a folder in the Folders collection has changed. As with the FolderAdd event a reference to the folder that was changed is passed into the event.

void folders_FolderAdd(Outlook.MAPIFolder Folder)
{
    MessageBox.Show(String.Format("A folder called {0} has changed.", Folder.Name));
}

Outlook Items

The Outlook Items collection object is used for accessing and enumerating items in Outlook folders. Although it is the best practice and far more efficient to use the GetTable method of the Folder object to enumerate items in a folder, you can still use the Items collection to perform a number of tasks.

C# code example

Outlook.Explorer currExplorer = null;
Outlook.Folder folder = null;
Outlook.Items items = null;
Outlook.ContactItem contact = null;
string contactList = string.Empty;
 
try
{
    currExplorer = OutlookApp.ActiveExplorer();
    folder = (Outlook.Folder)currExplorer.CurrentFolder;
 
    items = folder.Items;
 
    for (int i = 1; i <= items.Count; i++)
    {
        if (items[i] is Outlook.ContactItem)
        {
            contact = (Outlook.ContactItem)items[i];
            contactList += contact.FullName + Environment.NewLine;
            if (contact != null)
                Marshal.ReleaseComObject(contact);
        }
    }
    MessageBox.Show(contactList);
}
finally
{
    if (items != null)
    Marshal.ReleaseComObject(items);
    if (folder != null)
        Marshal.ReleaseComObject(folder);
    if (currExplorer != null)
        Marshal.ReleaseComObject(currExplorer);
}

Adding and removing items

To remove an item from the items collection you can invoke the Remove method and pass in the items index. To add an item to the Items collection you can use the Add method. You can specify the type of object to create by passing the type name to the method.

Outlook.Explorer currExplorer = null;
Outlook.Folder folder = null;
Outlook.Items items = null;
Outlook.ContactItem contact = null;
 
try
{
    currExplorer = OutlookApp.ActiveExplorer();
    folder = (Outlook.Folder)currExplorer.CurrentFolder;
 
    items = folder.Items;
    contact = items.Add(Outlook.OlItemType.olContactItem) 
        as Outlook.ContactItem;
    contact.Save();
 
}
finally
{
    if (contact != null)
        Marshal.ReleaseComObject(contact);
    if (items != null)
        Marshal.ReleaseComObject(items);
    if (folder != null)
        Marshal.ReleaseComObject(folder);
    if (currExplorer != null)
        Marshal.ReleaseComObject(currExplorer);
}

Items events

The Items object has similar events as the Folders object. However, there are a couple of things you need to look out for when using these events.

The ItemAdd event occurs when one or more item is added to the collection, however, this event does not fire when a large number of items are added at once.

void items_ItemAdd(object Item)
{
    Outlook.MailItem mail = null;
 
    try
    {
        if (Item is Outlook.MailItem)
        {
            mail = (Outlook.MailItem)Item;
            MessageBox.Show(
                String.Format(
                    "A new e-mail has been added, with subject : {0}", 
                    mail.Subject));
        }
    }
    finally
    {
        if (mail != null)
            Marshal.ReleaseComObject(mail);
    }
}

The ItemChange event fires when a new item in the collection is changed. As with the ItemAdd event a reference to the item is passed to the event as a parameter.

void items_ItemChange(object Item)
{
    Outlook.MailItem mail = null;
 
    try
    {
        if (Item is Outlook.MailItem)
        {
            mail = (Outlook.MailItem)Item;
            MessageBox.Show(
                String.Format(
                    "An e-mail has been added, with subject : {0}", 
                    mail.Subject));
        }
    }
    finally
    {
        if (mail != null)
            Marshal.ReleaseComObject(mail);
    }
}

Finally, the ItemRemove event occurs when an item is removed from the collection. Unfortunately, a reference to the item that has been removed is not passed into the event.

void items_ItemRemove()
{
    MessageBox.Show("An item was removed");
}

For more information about Outlook Items and Folder events please see Outlook Items and Folders Events explained.

Thank you for reading. Until next time, keep coding!

Available downloads:

This sample Outlook add-in was developed using Add-in Express for Office and .net:

C# Outlook add-in

Outlook 2013 add-in development in Visual Studio 2012 for beginners

55 Comments

  • Brian Tillman says:

    Good article. Consider correcting the spelling of “Atores” in the title to “Stores”.

  • Brian Tillman says:

    I see that you’ve done that now.

  • Dmitry Kostochko (Add-in Express Team) says:

    Hi Brian,

    Thank you for the heads up!

  • Max says:

    Hi Pieter,
    I created a User Store, adding a folder, added the path to the folders in ADXOlFormsCollectionItem.FolderNames and tied with ADXForm, but when i select these folders are not creating form!
    If I specify a folder from the outlook store for an exchange account form is created!
    How to fix it?

  • Pieter van der Westhuizen says:

    Hi Max,

    If I understood you correctly, you want to display a custom region for a folder? Make sure you’ve set the folder path correctly and that you specified the FormClassName.
    Also, make sure the ExplorerLayout property is set to the correct value.

    Hope this helps.

  • Max says:

    Yes, you understood me right.

    I set, for example:

    FormClassName = “…Forms.MainADXForm”
    FolderNames = {“\\\\MyStore\\Folder1″,”\\\\mymail@mail.com\\Folder2” }
    and ExplorerLayout = ADXOlExplorerLayout.WebViewPane.

    But for folder in the user store, outlook region is not created!
    for folder in outlook store all fine!

    If I set ExplorerLayout = ADXOlExplorerLayout.ReadingPane, for both folder created outlook region.

    How can this be?

  • Pieter van der Westhuizen says:

    Hi Max,

    Have a look at Andrei’s suggestion. It sounds like this might be your problem.

    Thanks for that Andrei!

  • Max says:

    Pieter, where i can see Andrei’s suggestion?

  • Pieter van der Westhuizen says:

    Whoops! My Bad, it was an email not a comment : )

    It sounds like you cannot create a WebViewPane form in a non-default message store. The reason and workarounds are described here:
    https://support.microsoft.com/kb/923933

    The actual registry key depends on the Outlook version used:
    12 – Outlook 2007
    14 – 2010
    15 – 2013

  • Max says:

    Pieter, thank you very much!!!

  • Nick says:

    If you create an IMAP account you get a new store for that Account, however “Personal Folders” is still the default store, and if try to get the default store programmatically it will be “Personal Folders”. How then can you programmatically figure out what the IMAP store is?

    You can’t simply look for a store named the same as your account email address, as you could go in and change the name of the IMAP store and now you have a name disconnect between your email account and IMAP store.

    You also can’t just look at the store type for a particular store because there might be multiple email accounts using IMAP.

  • Pieter van der Westhuizen says:

    Hi Nick,

    I’m not sure I understand what you need. Do you need to user to select a store or do you want to get the default store and check if it is an IMAP store?
    To get the default store use the DefaultStore property on the Session object : OutlookApp.Session.DefaultStore

    You can use the AccountType property of the Account object to check whether the account is an IMAP account.

    Hope this helps.

  • Thomas says:

    Can you pint me to this functionality in VBA, please?

  • Thomas says:

    *point*

  • Thomas says:

    Never mind. Translation completed.

  • Richard Corn says:

    I must be missing something. You show this construct:
    ns = OutlookApp.Session;
    accounts = ns.Accounts;

    But I don’t find Accounts as a property of outlook session object. Nor do I find .Stores as a property. I am trying to access account information, specifically for an mailitem about to be sent. I can’t seem to locate any reference Account in the namespaces I see in my project.

  • Pieter van der Westhuizen says:

    Hi Richard,

    The Accounts property on the Namespace object is only available on Outlook 2007 and up.

    In order to access/create accounts in Outlook 2003 and below, you’ll need to use Extended MAPI – which is not ideal to use in managed code. Take a look at this post on OutlookCode.com for more info.

    Hope this helps and good luck!

  • Andres Carrion says:

    Mil gracias por este blog, no sabes cuanto me gaste en encontrar esta explicación. Mil gracias!!!

  • Ashish says:

    Excellent article!!
    I am new to Microsoft office and working on a solution to extract MSG files from a PST file.

    Below is the code I got from various helps. However, while running this code, I am getting error on saving the MSG file. To be exact I am getting an error “An unhandled exception of type ‘System.Runtime.InteropServices.COMException’ occurred”
    while saving the file
    mailItem.SaveAs(@”\extracted\” + mailItem.Subject + “.msg”,OlSaveAsType.olMSG)

    Any suggestions what I am doing wrong?

    Sample Code:

    string pstFilePath = @”C:\Demo\Sample.pst”;
    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[1].GetRootFolder();
    // Traverse through all folders in the PST file
    Folders subFolders = rootFolder.Folders;
    foreach (Folder folder in subFolders)
    {
    Items items = folder.Items;
    foreach (object item in items)
    {
    if (item is MailItem)
    {
    // Retrieve the Object into MailItem
    MailItem mailItem = item as MailItem;
    Console.WriteLine(“Saving message {0} ….”, mailItem.Subject);
    // Save the message to disk in MSG format
    // TODO: File name may contain invalid characters [\ / : * ? ” |]
    mailItem.SaveAs(@”\extracted\” + mailItem.Subject + “.msg”, OlSaveAsType.olMSG);
    }
    }
    }
    // Remove PST file from Default Profile
    outlookNs.RemoveStore(rootFolder);

  • Pieter van der Westhuizen says:

    Hi Ashish,

    Looks like the problem might be the path where you’re saving the message file:
    mailItem.SaveAs(@”\extracted\” + mailItem.Subject + “.msg”, OlSaveAsType.olMSG);

    @”\extracted\” is not a valid file path you would need to change it to something like @”C:\Temp”

  • Ashish says:

    Hi Pieter,
    Thanks for the quick response. I did tried mentioning the path as you have told, but got the same error.

    However, one thing to notice here is that although I have Office 2013 installed on my system, I have not configured it. My mailbox is apparently still on lotus notes :(:( and would be moved to Outlook sooner.

    Could that be causing a issue? Although I dont think so considering all supporting files should be there with installation.

  • Pieter van der Westhuizen says:

    Hi Ashish,

    Did you start Outlook and does it have at least one mail account yet?

  • Ashish says:

    I just setup my outlook with a test account. However, I am getting the same error.

    “System.Runtime.InteropServices.COMException (0x800300FC): The operation failed.”

  • Pieter van der Westhuizen says:

    Hi Ashish,

    I’ve copied your code and do not get an error on the line you mentioned. I do however get an error on this line:
    outlookNs.RemoveStore(rootFolder);

    Where are you running the code from?From an add-in? Using VSTO or Add-in Express?

  • Ashish says:

    Hi Pieter,
    For this application, I just write a console application using VSTS 2013. I have added Microsoft.Office.Interop.Outlook reference to the project.

    Also, if the above code throws error while removing the PST from default profile, then any suggestions on what should be done here?

    Thanks

  • Ashish says:

    Hi Pieter,

    Just following up to know if you have any suggestions on the problem above?\

    Thanks

  • Pieter van der Westhuizen says:

    Hi Ashish,

    Upon closer inspection, the problem with the error you get on the mailItem.SaveAs line is that the mail subject contains invalid character. In order to save it to a local folder, first clean any invalid characters from the mail subject like so:

    string cleanedSubject = Regex.Replace(mailItem.Subject, @”[^\w\.@-]”, “”,RegexOptions.None, TimeSpan.FromSeconds(1.5));
    mailItem.SaveAs(@”C:\Temp\mails” + cleanedSubject + “.msg”, OlSaveAsType.olMSG);

    It seems the RemoveStore method returns an error when emails associated with another account has been pasted into the new store’s Inbox folder. It works if it does not contain any emails or if it contains email associated with its own account.

    Hope this helps!

  • Ashish says:

    Hi Pieter,

    Indeed that was the issue. Thanks much for your help.

  • Venkat says:

    I have a similar requirement as above.
    Extract Outlook Message files from PST file and then move the PST file to a different folder.

    Extracting mails work fine as suggested in above posts, but when I try to move PST using File.Move() to a different location it gives me error:
    “The process cannot access the file because it is being used by another process.”

    I tried closing the process before file.move() but still its not working.
    Process.GetProcessesByName(“outlook”)[0].Close();

    Also, when I go to task manager I find outlook.exe process running even though I donot have that opened.

    How to do this? I will highly appreciate any help.

  • Pieter van der Westhuizen says:

    Hi Venkat,

    Mmm..interesting question. Did you remove the store, using the RemoveStore method, before trying to delete the file?

  • Venkat says:

    Hi Pieter,

    Yes I am removing the store using nameSpace.RemoveStore menthod. I verified this in opened Outlook and the store is getting successfully removed.
    After that I have released all COM objects too.

    One thing to notice is that in debugging mode, if I close the outlook.exe process (in task manager) before doing File.Move(), it works perfectly.

    Do you want to see the code? I can share that with you.

  • Pieter van der Westhuizen says:

    Hi Venkat,

    Sure, please share the code. I can then test it on my side and see if I get the same problem.

  • Venkat says:

    Hi Pieter,

    Please find the code below. I have used some of the code shared in the above posts:

    using System;
    using System.IO;
    using System.Collections.Generic;
    using System.Linq;
    using System.Diagnostics;
    using System.Text;
    using System.Text.RegularExpressions;
    using System.Threading.Tasks;
    using System.Windows;
    using System.Runtime.InteropServices;
    using Microsoft.Office.Interop;
    using Microsoft.Office.Interop.Outlook;

    namespace ExtractMSGfromPST
    {
    class ExtractMSGfromPST
    {
    public static string folderPath = @”C:\Venkat\PSTFiles\”;
    public static string strBackupFolderPath = @”C:\Venkat\Backup\”;
    public static string strExtractedFolderPath = @”C:\Venkat\Extracted\”;

    static void Main(string[] args)
    {
    try {

    foreach (string pstFilePath in Directory.EnumerateFiles(folderPath, “*.pst”))
    {
    #region Extract MSG files from PST Files

    string strPSTFileName = fnGetPSTFileName(pstFilePath);
    fnExtractMSGFiles(strPSTFileName,pstFilePath);

    #endregion

    #region Move PST files to backup folder

    fnMoveExtractedPSTFiles(pstFilePath, strPSTFileName);

    #endregion
    }

    }

    catch (System.Exception ex)
    {
    //Log exception here
    }
    }

    private static void fnMoveExtractedPSTFiles(string pstFilePath, string strPSTFileName)
    {
    try
    {
    //first, delete target file if exists, as File.Move() does not support overwrite
    if (File.Exists(strBackupFolderPath + strPSTFileName))
    {
    File.SetAttributes(strBackupFolderPath + strPSTFileName, FileAttributes.Normal);
    File.Delete(strBackupFolderPath + strPSTFileName);
    }

    //Process.GetProcessesByName(“outlook”)[0].Close();

    File.Move(pstFilePath, strBackupFolderPath + strPSTFileName);

    }

    catch (System.Exception ex)
    {
    //Log exception here
    }
    }

    private static void fnExtractMSGFiles(string strPSTFileName, string pstFilePath)
    {
    Application app = new Application();
    NameSpace outlookNs = null;
    MAPIFolder rootFolder = null;
    Folders subFolders = null;
    Items items = null;

    try
    {
    outlookNs = app.GetNamespace(“MAPI”);

    // Add PST file (Outlook Data File) to Default Profile
    outlookNs.AddStore(pstFilePath);
    rootFolder = outlookNs.Stores[2].GetRootFolder();
    string strStoreName = outlookNs.Stores[2].DisplayName.ToString();

    // Traverse through all folders in the PST file
    subFolders = rootFolder.Folders;

    foreach (Folder folder in subFolders)
    {
    string stringFolderPath = strExtractedFolderPath + strPSTFileName + @”\” + strStoreName + @”\” + folder.Name.ToString();
    items = folder.Items;

    foreach (object item in items)
    {
    if (item is MailItem)
    {
    if (!Directory.Exists(stringFolderPath))
    Directory.CreateDirectory(stringFolderPath);

    // Retrieve the Object into MailItem
    MailItem mailItem = item as MailItem;

    // Save the message to disk in MSG format without invalid characters [\ / : * ? ” |]
    string mailSubject = Regex.Replace(mailItem.Subject, @”[^\w\.@-]”, “”, RegexOptions.None, TimeSpan.FromSeconds(1.5));
    mailItem.SaveAs(stringFolderPath + @”\” + mailSubject + “.msg”, OlSaveAsType.olMSG);

    if (mailItem != null)
    Marshal.FinalReleaseComObject(mailItem);

    }
    }
    }

    // Remove PST file from Default Profile
    outlookNs.RemoveStore(rootFolder);

    //Release com objects
    if (items != null)
    Marshal.ReleaseComObject(items);

    if (subFolders != null)
    Marshal.ReleaseComObject(subFolders);

    if (rootFolder != null)
    Marshal.ReleaseComObject(rootFolder);

    if (outlookNs != null)
    Marshal.ReleaseComObject(outlookNs);

    if (app != null)
    Marshal.ReleaseComObject(app);

    }

    catch (System.Exception ex)
    {
    //Log exception here
    }

    finally
    {
    //Release com objects
    if (items != null)
    Marshal.ReleaseComObject(items);

    if (subFolders != null)
    Marshal.ReleaseComObject(subFolders);

    if (rootFolder != null)
    Marshal.ReleaseComObject(rootFolder);

    if (outlookNs != null)
    Marshal.ReleaseComObject(outlookNs);

    if (app != null)
    Marshal.ReleaseComObject(app);
    }

    }

    private static string fnGetPSTFileName(string pstFilePath)
    {
    string strPSTFileName = String.Empty;
    int iPSTNameIndex = pstFilePath.LastIndexOf(@”\”);
    if (iPSTNameIndex != -1)
    {
    strPSTFileName = pstFilePath.Substring(iPSTNameIndex).Replace(@”\”, “”);
    }

    return strPSTFileName;
    }
    }
    }

  • Venkat says:

    Hi Pieter,

    Were you able to replicate the issue at your end?

  • Pieter van der Westhuizen says:

    Hi Venkat,

    I took a quick look at it. Problem is it takes a while for the outlook process to quit. I’ve managed to get it working using the following:

    var process = Process.GetProcessesByName(“outlook”);
    process[0].Kill();
    Thread.Sleep(1000);
    File.Move(pstFilePath, strBackupFolderPath + strPSTFileName);

    Not sure if there is a better way, but the above worked :)

    Hope this helps. Good luck!

  • Venkat says:

    Hi Pieter,

    I tried that earlier, but the sample files I have are very huge and I am not sure if its contributing to the error. I will try to see if there any other way or else would increase the time. Will keep you all posted on it. Thanks

  • Rissardi says:

    Hi,

    Nice article!!

    But why we should use GetTable method of the Folder object to enumerate items in a folder??
    And how much performance I lose using Items collection.

    Tanks,
    Rissardi.

  • Pieter van der Westhuizen says:

    Hi Rissardi,

    You certainly do not have to use the GetTable method, using the items collection is perfectly acceptable. However, the Table object was added in Outlook 2007 to address certain performance concerns with the Items collection. So when working with large amounts of data the GetTable method,which returns a Table object, is the prefered choice.

    In essence think of the Table object as a readonly rowset, that only allows reading of the data and does not allow any changes to be made. It is a light-weight in memory datasteam. It is comparable to the DataReader object in .Net – which allows for very fast data reading.

    Hope this helps!

  • AJAY says:

    Hi All,

    I am getting the following issue

    Outlook failed to add the personal store to this session

    Also can you tell me which dll is used here?

  • Pieter van der Westhuizen says:

    Hi Ajay,

    Where do you get the error? Can you post the code you’re using?
    The dll’s used for this example are:
    Microsoft.Office.Interop.Outlook.dll
    Office.dll
    AddinExpress.MSO.2005

  • Martin Loreck says:

    Well, good job, only the part with the folders loop has a little mistake

    for (int i = 1; i < folders.Count; i++)

    Change it into
    for (int i = 1; i <= folders.Count; i++)

    The condition was wrong so that the last item was missed
    However a very well written

  • Steven S says:

    I’m sorry I’m late to the discussion. This is a very helpful article. Is it possible to write this code so that it ran in a standalone Windows exe or service (i.e., versus running only from within Outlook itself)?

    Thanks in advance for your help.

  • Gimmy says:

    My Outlook account is made of two mailbox.

    I am able to identify the root of the primary mailbox with the following

    Public Sub AppResponse(Item As Outlook.MailItem)
    Dim objNameSpace As Outlook.NameSpace
    Dim objInboxFolder As Outlook.MAPIFolder
    Set objNameSpace = Application.Session
    Set objInboxFolder = objNameSpace.GetDefaultFolder(olFolderInbox)

    How can I generalize the interception of the specific Inbox root folder to which a processed email belongs?

    I have tried with

    Set objInboxFolder = Item.Parent

    but if the mail belongs to a subfolder then I just get the parent folder, nor the main root.

    Thanks
    Gim

  • Andrei Smolin (Add-in Express Team) says:

    Hello Gim,

    I don’t understand if you process incoming emails, outgoing emails, or some (all) emails. To get the store, the folder is located in, you call Outlook.MAPIFolder.Store, then call Store.GetDefaultFolder() to get the inbox folder on that store.

  • Peter says:

    Hi, where is the class OutlookApp? Don’t know where i can import it. thanks
    Peter

  • Andrei Smolin (Add-in Express Team) says:

    Hello Peter,

    When an Office add-in gets loaded, Office supplies it with a reference to the Application object (from the host’s object model). OutlookApp is a property that points to such an Application object; the property is declared on the add-in module; the add-in module makes sense only if you use Add-in Express. In all other circumstances, you should replace OutlookApp with an Outlook.Application object that you obtain yourself.

  • Massimo says:

    Great Article!! Thank you so much

  • zipi says:

    hey
    I have built an add-in for Outlook
    and I want it to be active only at a specipic account
    how can i do that?
    thanks

  • Andrei Smolin (Add-in Express Team) says:

    Hello Zipi,

    You can’t do this. Instead, use Outlook events to show/hide the UI of your add-in.

    Put an Outlook Events component (ADXOutlookAppEvents) onto the add-in module and use the ExplorerFolderSwitch (or, maybe, ExplorerFolderSwitch) to detect the account and show/hide the UI: Ribbon controls and panes. In addition, you may need to start/stop handling Outlook events (other than ExplorerFolderSwitch).

  • zipi says:

    Thanks for the feedback
    The problem is that the add-in is active even without pressing the ribbon
    It keeps every email that goes in and I only need a certain expense
    You have another idea for me

  • Andrei Smolin (Add-in Express Team) says:

    Hello Zipi,

    There’s no way to enable/disable the add-in in this way. The only way the Outlook object model provides is to detect the account used and show/hide the UI and connect to/disconnect from events. BTW, you may prefer to connect to events permanently and use a Boolean flag so that event handlers might choose whether to perform or not to perform related functionality.

  • Leon Lorge says:

    thanks for sharing!

  • Robert Stratton says:

    I’m trying to get a list of contacts from a .PST file that is not the default.
    I can “add” said .PST file to the “stores” but so far haven’t figured out how to access and retrieve a list of contacts from that (non-default) store (.PST file).
    By the way, this is a Visual Basic.NET 2022 desktop app NOT a VBA app/macro.
    Any suggestions/pointers?
    Thanks, Bob

  • Andrei Smolin (Add-in Express Team) says:

    Hello Robert,

    See Store.GetDefaultFolder(); https://learn.microsoft.com/en-us/office/vba/api/outlook.store.getdefaultfolder. If contacts are in a non-default Contacts folder(s), you’ll need to scan all folders of that store checking the Folder.DefaultItemType property; see https://learn.microsoft.com/en-us/office/vba/api/outlook.folder.defaultitemtype.

Post a comment

Have any questions? Ask us right now!