While working on a VSTO add-in for Microsoft Outlook, I came across the need to access the headers of an email, to parse out X-CustomProperty tags that were put in by an application that sent the emails. However, I couldn’t find a Headers property in the Outlook object model, so below is an attempt to create one.
The Regex used is courtesy of John Gietzen’s answer on this stackoverflow question.
using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; using Microsoft.Office.Interop.Outlook; public static class MailItemExtensions { private const string HeaderRegex = @"^(?<header_key>[-A-Za-z0-9]+)(?<seperator>:[ \t]*)" + "(?<header_value>([^\r\n]|\r\n[ \t]+)*)(?<terminator>\r\n)"; private const string TransportMessageHeadersSchema = "http://schemas.microsoft.com/mapi/proptag/0x007D001E"; public static string[] Headers(this MailItem mailItem, string name) { var headers = mailItem.HeaderLookup(); if (headers.Contains(name)) return headers[name].ToArray(); return new string[0]; } public static ILookup<string, string> HeaderLookup(this MailItem mailItem) { var headerString = mailItem.HeaderString(); var headerMatches = Regex.Matches (headerString, HeaderRegex, RegexOptions.Multiline).Cast<Match>(); return headerMatches.ToLookup( h => h.Groups["header_key"].Value, h => h.Groups["header_value"].Value); } public static string HeaderString(this MailItem mailItem) { return (string)mailItem.PropertyAccessor .GetProperty(TransportMessageHeadersSchema); } }
Sample usage:
string[] preparedByArray = mailItem.Headers("X-PreparedBy"); string preparedBy; if (preparedByArray.Length == 1) preparedBy = preparedByArray[0]; else preparedBy = ""; string allHeaders = mailItem.HeaderString();
Edit 2011/08/05:
Thanks to Rob for the heads-up. I updated the code to return a Lookup instead of a Dictionary – this handles the case of multiple headers with the same name.
4 Comments
Very nice! It probably would’ve taken me a week of digging around in MSDN (accompanied by much cursing) to figure this out on my own, so big thanks to you (and google =).
However, my attempt to utilize it is throwing
“ArgumentException was unhandled by user code”
“An item with the same key has already been added.”
on line 25, the ToDictionary() call.
I suspect it’s because the email I’m testing on has THREE “Received:” headers, which isn’t unusual at all.
Since my immediate need is merely to check for the presence of a particular header in a MailItem, the HeaderString() method is usable. But I figured you might want an early heads-up in case someone needs the additional lookup functionality.
(I’d normally try to provide some helpful suggestions or patch it, but I’m a C# noob and I don’t even know what the “=>” operator does =)
Thanks Rob, I updated the post with code that should work with multiple headers.
Hi,
Can we use the same approach to add custom headers to out bound messages?
I’m trying to build and OutlookAddin that will enable me add a custom header for any mail i send from my outlook.
Thanks
Brilliant. Time and pain saver. Thank you.