Click here to Skip to main content
15,886,791 members
Articles / Programming Languages / C#

Extracting Email Addresses from Outlook Mailboxes using C#

Rate me:
Please Sign up or sign in to vote.
4.86/5 (5 votes)
27 Nov 2015CPOL3 min read 17.4K   11   1
Extracting Email Addresses from Outlook Mailboxes using C#

Introduction

Sometimes, it's handy to be able to easily extract a list of email addresses from your Outlook PST or OST file.

The 'old fashioned' way of doing this is to export the mailbox to a CSV file, and only include email addresses as a field.

But with large mailboxes, this can be time consuming and cumbersome, and Outlook will often include internal sender IDs instead of email addresses, which are not overly useful.

There are also a number of commercial applications to extract email addresses, but why pay money when you can just use a few lines of code? :-)

The Application

This application performs a few simple tasks required to extract a listing of email addresses (and a counter for how often each is used).

  1. Find the root folder in the Outlook Datastore
  2. Iterate recursively through the folder structure
  3. Iterate through each email message in each folder
  4. Parse each message, saving its sender address and all recipients

Which Email Addresses Does It Use?

Currently, the application extracts each message's sender email address, and it also iterates through all CC'd addresses.

One limitation is that your email address is likely to be in the list of recipients (how else would you have received the message!), so it is likely your address will have the highest counter value.

It is relatively trivial to exclude your own email address - simply ammend the add_address_to_list() function to check for your address and not add it if found.

Prerequisites

adding the Microsoft.Office.Interop.Outlook assembly reference in visual studio

Firstly, create a C# console application in Visual Studio, targeting the .NET 4.5 or higher framework.

The application makes use of the Microsoft.Office.Interop.Outlook assembly, so you'll need to add this as a reference in your project.

The Outlook Primary Interop Assembly (PIA) Reference provides help for developing managed applications for Outlook 2013 and 2016. It extends the Outlook 2013 and 2016 Developer Reference from the COM environment to the managed environment, allowing to you interact with Outlook from a .NET application.

You also need to have Microsoft Outlook installed on your PC - otherwise the Interop assembly has nothing to talk to.

Learn more on MSDN.

Iterating through Outlook Accounts

Before we can go through each folder and email in Outlook, we need to find an actual account, and build the root folder from this.

The root folder is in the format \\foldername\, and the inbox is located one level below this, at \\foldername\Inbox\.

To do this, we simply iterate through the Outlook.Application.Session.Accounts collection.

C#
Outlook.Application Application = new Outlook.Application();
Outlook.Accounts accounts = Application.Session.Accounts;
foreach (Outlook.Account account in accounts)
    {
        Console.WriteLine(account.DisplayName);
    }    

From these, we can derive the root folder name.

Recursing through Folders

Using the function below, we initially pass it the root folder. It then looks for any child (sub) folders, and passes this to itself recursively, following the folder structure until it reaches the end.

C#
static void EnumerateFolders(Outlook.Folder folder)
{
    Outlook.Folders childFolders = folder.Folders;
    if (childFolders.Count > 0)
    {
        foreach (Outlook.Folder childFolder in childFolders)
        {
            // We only want Inbox folders - ignore Contacts and others
            if (childFolder.FolderPath.Contains("Inbox"))
            {
                Console.WriteLine(childFolder.FolderPath);
                // Call EnumerateFolders using childFolder, 
                // to see if there are any sub-folders within this one
                EnumerateFolders(childFolder);
            }
        }
    }
}

Iterating through Emails and Retrieving Email Addresses

Using the function below, we retrieve the sender address, and then iterate through the recipients collection, passing all the addresses found to a function add_address_to_list. The function simply searches a dynamic array to see whether the address has been found previously, and if so, it increments its counter. This keeps track of how many times an email address has been found.

If the function can't find the address in the array, it adds it.

C#
string senderAddress = mailitem.Sender.Address; 
add_address_to_list(senderAddress);      
                    
Outlook.Recipients recipients = olMailItem.Recipients;
foreach (Outlook.Recipient recipient in recipients) 
{
    add_address_to_list(recipient.Address); 
}

static void add_address_to_list(string emailAddress)
{
    if (emailAddress.Contains("@") && emailAddress.Contains("."))
    {
        bool found = false;
        for (int i = 0; i < emailAddresses.Count; i++)
        {
            if (emailAddresses[i] == emailAddress)
            {
                // email address was found, so just increment it's counter
                found = true;
                emailAddressesCounter[i]++;
            }
        }
        if (!found)
        {
            // email address wasn't found, so add it to the array
            emailAddresses.Add(emailAddress);
            emailAddressesCounter.Add(1); //starts with a count of 1
            Console.WriteLine(emailAddresses.Count + ": Added " + emailAddress);
        }
    }
}

Download

You can download the code to this project from GitHub, or check out the code below.

Download Follow @matthewproctor <script async defer id="github-bjs" src="https://buttons.github.io/buttons.js"></script>

The Full Code

program.cs

C#
///
/// Outlook Email Address Extractor 
/// Version 0.1
/// Build 2015-Nov-18
/// Written by Matthew Proctor
/// www.matthewproctor.com
///
using System;
using System.Linq;
using System.IO;
using System.Collections.Generic;
using Outlook = Microsoft.Office.Interop.Outlook;

namespace OutlookEmailAddressExtractor
{
    class Program
    {

        // Array to store email addresses and counts
        public static List<string> emailAddresses = new List<string>();
        public static List<int> emailAddressesCounter = new List<int>();

        static void Main(string[] args)
        {
            EnumerateAccounts();
            //EnumerateFoldersInDefaultStore();
            //Console.WriteLine("Total file size:" + totalfilesize);
        }

        static void EnumerateFoldersInDefaultStore()
        {
            Outlook.Application Application = new Outlook.Application();
            Outlook.Folder root = Application.Session.DefaultStore.GetRootFolder() as Outlook.Folder;
            EnumerateFolders(root);
        }

        // Uses recursion to enumerate Outlook subfolders.
        static void EnumerateFolders(Outlook.Folder folder)
        {
            Outlook.Folders childFolders = folder.Folders;
            if (childFolders.Count > 0)
            {
                foreach (Outlook.Folder childFolder in childFolders)
                {
                    // We only want Inbox folders - ignore Contacts and others
                    if (childFolder.FolderPath.Contains("Inbox"))
                    {
                        // Write the folder path.
                        Console.WriteLine(childFolder.FolderPath);
                        // Call EnumerateFolders using childFolder, 
                        // to see if there are any sub-folders within this one
                        EnumerateFolders(childFolder);
                    }
                }
            }
            Console.WriteLine("Checking in " + folder.FolderPath);
            IterateMessages(folder);
        }

        static void IterateMessages(Outlook.Folder folder)
        {
            // attachment extensions to save
            string[] extensionsArray = { ".pdf", ".doc", ".xls", 
            ".ppt", ".vsd", ".zip", ".rar", 
            ".txt", ".csv", ".proj" };

            // Iterate through all items ("messages") in a folder
            var fi = folder.Items;
            if (fi != null)
            {
                try
                {
                    foreach (Object item in fi)
                    {
                        Outlook.MailItem mailitem = (Outlook.MailItem)item;

                        string senderAddress = mailitem.Sender.Address;
                        add_address_to_list(senderAddress);

                        Outlook.Recipients recipients = mailitem.Recipients;
                        foreach (Outlook.Recipient recipient in recipients)
                        {
                            add_address_to_list(recipient.Address);
                        }
                    }
                }
                catch (Exception e)
                {
                    //Console.WriteLine("An error occurred: '{0}'", e);
                }
            }
        }

        static void add_address_to_list(string emailAddress)
        {
            if (emailAddress.Contains("@") && emailAddress.Contains("."))
            {
                bool found = false;
                for (int i = 0; i < emailAddresses.Count; i++)
                {
                    if (emailAddresses[i] == emailAddress)
                    {
                        // email address was found, so just increment it's counter
                        found = true;
                        emailAddressesCounter[i]++;
                    }
                }
                if (!found)
                {
                    // email address wasn't found, so add it to the array
                    emailAddresses.Add(emailAddress);
                    emailAddressesCounter.Add(1); //starts with a count of 1
                    Console.WriteLine(emailAddresses.Count + ": Added " + emailAddress);
                }
            }
        }

        // Retrieves the email address for a given account object
        static string EnumerateAccountEmailAddress(Outlook.Account account)
        {
            try
            {
                if (string.IsNullOrEmpty(account.SmtpAddress) || string.IsNullOrEmpty(account.UserName))
                {
                    Outlook.AddressEntry oAE = account.CurrentUser.AddressEntry as Outlook.AddressEntry;
                    if (oAE.Type == "EX")
                    {
                        Outlook.ExchangeUser oEU = oAE.GetExchangeUser() as Outlook.ExchangeUser;
                        return oEU.PrimarySmtpAddress;
                    }
                    else
                    {
                        return oAE.Address;
                    }
                }
                else
                {
                    return account.SmtpAddress;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                return "";
            }
        }

        static void EnumerateAccounts()
        {
            Console.Clear();
            Console.WriteLine("Outlook Email Address Extractor v0.1");
            Console.WriteLine("------------------------------------");
            int id;
            Outlook.Application Application = new Outlook.Application();
            Outlook.Accounts accounts = Application.Session.Accounts;

            string response = "";
            while (true == true)
            {

                id = 1;
                foreach (Outlook.Account account in accounts)
                {
                    Console.WriteLine(id + ":" + EnumerateAccountEmailAddress(account));
                    id++;
                }
                Console.WriteLine("Q: Quit Application");

                response = Console.ReadLine().ToUpper();
                if (response == "Q")
                {
                    Console.WriteLine("Quitting");
                    return;
                }
                if (response != "")
                {
                    if (Int32.Parse(response.Trim()) >= 1 && Int32.Parse(response.Trim()) < id)
                    {
                        Console.WriteLine("Processing: " + 
                        accounts[Int32.Parse(response.Trim())].DisplayName);
                        Console.WriteLine("Processing: " + 
                        EnumerateAccountEmailAddress(accounts[Int32.Parse(response.Trim())]));

                        Outlook.Folder selectedFolder = 
                        Application.Session.DefaultStore.GetRootFolder() as Outlook.Folder;
                        selectedFolder = GetFolder(@"\\" + 
                        accounts[Int32.Parse(response.Trim())].DisplayName);
                        EnumerateFolders(selectedFolder);
                        Console.WriteLine("Sorting results.");
                        sort_email_addresses();
                        Console.WriteLine("Saving results.");
                        save_email_addresses();
                        Console.WriteLine("Finished Processing " + 
                        accounts[Int32.Parse(response.Trim())].DisplayName);
                        Console.WriteLine("Addresses Found " + emailAddresses.Count);
                        Console.WriteLine("");
                    }
                    else
                    {
                        Console.WriteLine("Invalid Account Selected");
                    }
                }
            }
        }

        // Saves the output as a CSV file in the format emailaddress,counter 
        // in the current directory        
        static void save_email_addresses()
        {
            Console.WriteLine("Saving to: " + 
            Directory.GetCurrentDirectory() + @"\output.csv");
            using (StreamWriter writetext = 
            new StreamWriter(Directory.GetCurrentDirectory() + @"\output.csv"))
            {
                writetext.WriteLine("emailaddress,counter");
                for (int i = 0; i < emailAddresses.Count; i++)
                {
                    writetext.WriteLine(emailAddresses[i] + "," + emailAddressesCounter[i]);
                }
            }
        }

        // Uses a basic bubble sort to order the results by the email address
        // and persisting the position of the counter. 
        static void sort_email_addresses()
        {
            for (int i = 1; i < emailAddresses.Count; i++)
            {
                for (int d = 0; d < i; d++)
                {
                    if (String.Compare(emailAddresses[d], emailAddresses[i]) > 0)
                    {
                        string tempEmailAddress = emailAddresses[d];
                        emailAddresses[d] = emailAddresses[i];
                        emailAddresses[i] = tempEmailAddress;
                        int tempEmailAddressCount = emailAddressesCounter[d];
                        emailAddressesCounter[d] = emailAddressesCounter[i];
                        emailAddressesCounter[i] = tempEmailAddressCount;
                    }
                }
            }
        }

        // Returns Folder object based on folder path
        static Outlook.Folder GetFolder(string folderPath)
        {
            Console.WriteLine("Looking for: " + folderPath);
            Outlook.Folder folder;
            string backslash = @"\";
            try
            {
                if (folderPath.StartsWith(@"\\"))
                {
                    folderPath = folderPath.Remove(0, 2);
                }
                String[] folders = folderPath.Split(backslash.ToCharArray());
                Outlook.Application Application = new Outlook.Application();
                folder = Application.Session.Folders[folders[0]] as Outlook.Folder;
                if (folder != null)
                {
                    for (int i = 1; i <= folders.GetUpperBound(0); i++)
                    {
                        Outlook.Folders subFolders = folder.Folders;
                        folder = subFolders[folders[i]] as Outlook.Folder;
                        if (folder == null)
                        {
                            return null;
                        }
                    }
                }
                return folder;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                return null;
            }
        }
    }
}

Testing

I've tested this code on mailboxes hosted with an on-premises Exchange 2013 environment, Office 365 and a POP3/IMAP mailbox as well - all functioning exactly the same.

Further Reading

The links below provide more information on how to use the Outlook Interop service.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
CEO Kutamo and ErrLog.IO
Australia Australia
Pluralsight Author, .Net Developer, Writer & Blogger

http://www.kutamo.com/
http://www.errlog.io/
http://www.matthewproctor.com/
http://www.pluralsight.com/author/matthew-proctor

I am an Australian IT professional based in Melbourne, Victoria, Australia.

I'm a polyglot programmer, being proficient in a number of languages and frameworks including C#, VB.Net, F#, Javascript, Perl, Powershell and Z80 & 6502 assembly. Smile | :)

Comments and Discussions

 
GeneralMy vote of 5 Pin
tenriquez3917-Jan-20 8:43
tenriquez3917-Jan-20 8:43 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.