Extraer direcciones de email del buzón de Outlook usando C#

A veces es muy útil poder extraer fácilmente la lista de direcciones de email de tu PST de Outlook o de un archivo OST. La manera más 'pasada de moda' de hacer esto es exportar el buzón a un archivo CSV, y sólo te incluirán las direcciones de email como un campo. Pero con buzones grandes, esto puede llevar mucho más tiempo y, sinceramente, es muy engorroso, y a menudo se incluyen IDs de los senders en vez de las direcciones de correo electrónico, que no son demasiado útiles. También existen una serie de aplicaciones comerciales para extraer direcciones de correo electrónico, pero ¿por qué pagar por ello cuando se pueden utilizar un par de líneas de código?

La aplicación

La aplicación que te vamos a presentar hoy realiza las tareas requeridas para extraer la lista de direcciones de correo electrónico (y un contador con la frecuencia de uso de cada uno). Para ello:

  • Busca la carpeta raíz en el almacén de datos de Outlook
  • Itera recursivamente a través de la estructura de carpetas
  • Itera a través de cada mensaje de email en cada una de las carpeta
  • Analiza cada mensaje, guardando la dirección del remitente y todos sus recipientes

¿Qué direcciones de correo electrónico se utilizan?

Actualmente la aplicación extrae la dirección de correo electrónico del remitente de cada mensaje, y también itera a través de todas las direcciones CC'd. Una de las limitaciones es que tu dirección de correo electrónico es probable que esté en la lista de destinatarios (¿sino cómo habrías recibido el mensaje?), por lo que es probable que tu dirección tendrá el valor más alto del contador. Este problema es relativamente trivial, solo tienes que comprobar si tu dirección de correo electrónico está en la lista, y si es afirmativo, se retira y punto.

Prerrequisitos

En primer lugar, crear una aplicación de consola de C # en Visual Studio, .NET 4.5 o superior. La aplicación hace uso del conjunto Microsoft.Office.Interop.Outlook, por lo que tendrás que añadir esto como una referencia en tu proyecto. La PIA proporciona ayuda para el desarrollo de aplicaciones administradas para Outlook 2013 y 2016. También necesitas tener Microsoft Outlook instalado en tu PC.

Iteración a través de cuentas de Outlook

Antes de que podamos recorrer cada carpeta y el correo electrónico en Outlook, tenemos que encontrar una cuenta real, y construir la carpeta raíz de esto mismo. La carpeta raíz tiene el formato nombredecarpeta, y la bandeja de entrada se encuentra un nivel por debajo de este, en nombredecarpetaInbox. Para ello, simplemente recorre el Outlook.Application.Session.Accounts.

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

A partir de esto, podemos saber el nombre de la carpeta raíz.

Recorrer las carpetas

Usando la función de abajo, inicializamos el paso a la carpeta raíz. A continuación, busca cualquier hijo (sub) carpeta, y recórrelo de forma recursiva, siguiendo la estructura de carpetas hasta que llegues al final.

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

Recorriendo los correos electrónicos y recuperando las direcciones

Usando la función de más abajo, recuperamos la dirección del remitente, y luego recorremos la colección de destinatarios, pasando todas las direcciones que encuentres a una función add_address_to_list. La función es simple, busca en un array dinámico para ver si la dirección ha sido encontrada previamente, y si es así, incrementa el contador. Esto hace un seguimiento de las veces que se ha encontrado una dirección de correo electrónico. Si la función no puede encontrar la matriz, la crea.

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

Código Completo

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 emailAddresses = new List();
        public static List emailAddressesCounter = new List();

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

    }

}

Agradecer a Matthew Proctor el habernos proporcionado este código.

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP