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).
- Find the root folder in the Outlook Datastore
- Iterate recursively through the folder structure
- Iterate through each email message in each folder
- 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
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.
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.
static void EnumerateFolders(Outlook.Folder folder)
{
Outlook.Folders childFolders = folder.Folders;
if (childFolders.Count > 0)
{
foreach (Outlook.Folder childFolder in childFolders)
{
if (childFolder.FolderPath.Contains("Inbox"))
{
Console.WriteLine(childFolder.FolderPath);
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.
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)
{
found = true;
emailAddressesCounter[i]++;
}
}
if (!found)
{
emailAddresses.Add(emailAddress);
emailAddressesCounter.Add(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
using System;
using System.Linq;
using System.IO;
using System.Collections.Generic;
using Outlook = Microsoft.Office.Interop.Outlook;
namespace OutlookEmailAddressExtractor
{
class Program
{
public static List<string> emailAddresses = new List<string>();
public static List<int> emailAddressesCounter = new List<int>();
static void Main(string[] args)
{
EnumerateAccounts();
}
static void EnumerateFoldersInDefaultStore()
{
Outlook.Application Application = new Outlook.Application();
Outlook.Folder root = Application.Session.DefaultStore.GetRootFolder() as Outlook.Folder;
EnumerateFolders(root);
}
static void EnumerateFolders(Outlook.Folder folder)
{
Outlook.Folders childFolders = folder.Folders;
if (childFolders.Count > 0)
{
foreach (Outlook.Folder childFolder in childFolders)
{
if (childFolder.FolderPath.Contains("Inbox"))
{
Console.WriteLine(childFolder.FolderPath);
EnumerateFolders(childFolder);
}
}
}
Console.WriteLine("Checking in " + folder.FolderPath);
IterateMessages(folder);
}
static void IterateMessages(Outlook.Folder folder)
{
string[] extensionsArray = { ".pdf", ".doc", ".xls",
".ppt", ".vsd", ".zip", ".rar",
".txt", ".csv", ".proj" };
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)
{
}
}
}
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)
{
found = true;
emailAddressesCounter[i]++;
}
}
if (!found)
{
emailAddresses.Add(emailAddress);
emailAddressesCounter.Add(1); Console.WriteLine(emailAddresses.Count + ": Added " + emailAddress);
}
}
}
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");
}
}
}
}
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]);
}
}
}
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;
}
}
}
}
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.