Question

I am working on a software where i am able to retrieve the inbox and sent items from outlook. What i want to do is to relate the inbox emails with replies (if someone has sent a reply to that email). The list should be displayed in this order

Sender@abc.com Incoming Subject Received Time sender@abc.com Reply Subject Sent time

What i am planning to do is to retrieve inbox items in one datatable and the sent items in another datatable. It reads the emails one by one on the basis of sender email and the subject, then searches that sender and email in the sent items and if it matches, merge that to a third datatable.

is there any other better way to do so?

Here is the code:

 private DataTable GetInboxItems()

    {
        DataTable inboxTable;
        //try
        //{
        filter = "[ReceivedTime] >= '" + dtpStartDate.Value.ToString("dd/MM/yyyy 12:00 AM") + "' and [ReceivedTime] <= '" + dtpEndDate.Value.ToString("dd/MM/yyyy  11:59 PM") + "'";
        Outlook.Application outlookApp = GetApplicationObject();
        Outlook.Folder root = outlookApp.Session.DefaultStore.GetRootFolder() as Outlook.Folder;
        EnumerateFolders(root);
        //string filter = "[ReceivedTime] > '" + dtpStartDate.Value.ToString("dd/MM/yyyy") + "'";

        //inbox
        Outlook.MAPIFolder inboxFolder = outlookApp.Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox);
        inboxTable = CreateTable();
        int count = 0;


        if (inboxFolder.Items.Count > 0)
        {

            var restrictedItems = inboxFolder.Items.Restrict(filter);
            restrictedItems.Sort("[ReceivedTime]", true); //descending
            //foreach (var item in inboxFolder.Items)
            foreach (var item in restrictedItems)
            {
                var mail = item as Outlook.MailItem;
                if (mail != null)
                {
                    //try
                    //{
                    DataRow row = inboxTable.NewRow();
                    //row["sn"] = (++count).ToString();
                    row["sn"] = mail.EntryID + " " + mail.ReceivedByEntryID;
                    row["MailType"] = "Inbox";
                    row["SenderName"] = mail.SenderName;
                    row["SenderEmail"] = mail.SenderEmailAddress;
                    row["ReceivedDate"] = mail.ReceivedTime;
                    row["Subject"] = mail.Subject;
                    row["Body"] = mail.Body != null ? (mail.Body.Length > 25 ? mail.Body.Substring(0, 25) : mail.Body) : null;
                    //row["Body"] = mail.Body != null ? mail.Body : "";
                    row["MailSize"] = mail.Size.ToString();
                    string attachments = null;
                    if (mail.Attachments.Count > 0)
                    {
                        foreach (var attachment in mail.Attachments)
                        {
                            if (((Outlook.Attachment)attachment) != null)
                                //attachments = ((Outlook.Attachment)attachment).FileName + " " + ((Outlook.Attachment)attachment).Size.ToString() + ", ";
                                attachments += (((Outlook.Attachment)attachment).Size / 1024).ToString() + " KB, ";
                        }
                    }


                    row["AttachmentCount"] = mail.Attachments.Count;
                    if (attachments != null)
                        row["AttachmentSize"] = attachments.Substring(0, attachments.Length - 2);

                    inboxTable.Rows.Add(row);
                }
                //catch (Exception ex)
                //{

                //    return null;
                //}

            }
        }

        return inboxTable;
    }
Was it helpful?

Solution

I've made this kind of stuff in an outlook add-in

There is no 100% way to make it ...
The problem is that the conversation ID is not always kept by other software. So you need to use a set of data to link email to their answers:
- Message-ID: this is available in the email headers. Sent items doesn't have this :/
- In-Reply-To: this is also in the email headers
- Topic ID

For the topic ID, I retrieve values in this order (I take the first available):
- MailItem.ConversationIndex: Each reply add bytes to the conversation index
- Reference header

Then, I link email to their reply using topicID, email have the same first X characters than reply. Example original email topic id = abc, reply = abcdef For all mails than cannot be linked using conversation id, I try to link using Message-ID & In-Reply-To ID

Problem will particularly comes from email sent by outlook (no Message-ID) then user reply without Reference/ConversationIndex header... you'll not have any way to link both mail together.

Hope it helps

EDIT: Here's some code. I've copy/pasted code from different class/method to create a single method, so it may not compile. Take it more as a pseudo-code.

public SimpleTree<MailData> CreateTree(List<MailData> mails)
{
    mails.Sort((m1, m2) => m1.TopicId == m2.TopicId ? m2.CreationDate.CompareTo(m1.CreationDate) : m1.TopicId.CompareTo(m2.TopicId));

    var tree = new SimpleTree<MailData>();

    var i = 0;
    while (i < mails.Count)
    {
        var node = tree.Children.Add(mails[i]);
        var topicId = mails[i].TopicId;
        var start = i + 1;
        while (start < mails.Count 
            && !string.IsNullOrEmpty(topicId) 
            && !string.IsNullOrEmpty(mails[start].TopicId) 
            && mails[start].TopicId.StartsWith(topicId))
        {
            node.Children.Add(mails[start]);
            start++;
        }
        i = start;
    }

    // Handle email where TopicId are different, but ParentId is filled with correct value
    for (int j = tree.Children.Count - 1; j >= 0; j--)
    {
        var child = tree.Children[j];
        if (child.Children.Count == 0 && !string.IsNullOrEmpty(child.Value.ParentId))
        {
            var parentNode = tree.FindNode(s => s != null && s.MessageId == child.Value.ParentId);
            if (parentNode != null && parentNode != child)
                parentNode.Children.Add(child);
        }
    }

    return tree;
}

MailData is a class with the 3 fields needed as explained before:

  • MessageID (from Message-ID header)
  • ParentId (from In-Reply-To header)
  • TopicId (from ConversationIndex or Reference header)

SimpleTree<> is a class to create tree, it's in fact a node with children. Nothing special or related to email here. The .Value property refer to the data associated to the node (MailData here)

The goal is to sort on the TopicId so that we can construct the tree in 1 loop Then I check all the mail in the tree root to check if we can move them under another mail usine MessageId/ParentId

Just remember that it create a one-level tree, something like:

  • Mail A
    • Reply AA
    • Reply AAA
  • Mail B
    • Reply BB
    • Reply BBB

But you would need something like this:

  • Mail A
    • Reply AA
      • Reply AAA
  • Mail B
    • Reply BB
      • Reply BBB
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top