HOWTO: Get Email Messages from Exchange to SharePoint
Many people ask about how to do this, so I thought I'd write up a sample. This sample basically searches the inbox of a user and then does an HTTP GET against the DAV:href to get the EML file and then does an HTTP PUT to upload it to a SharePoint document library.
using System; using System.Web; using System.Xml; using System.Net; using System.Text; namespace UploadEmlToSharePoint { /// <summary> /// Summary description for Class1. /// </summary> class Class1 { static System.Net.CredentialCache MyCredentialCache; /// <summary> /// The main entry point for the application. /// </summary> [STAThread] static void Main(string[] args) { System.Net.HttpWebRequest Request; System.Net.WebResponse Response; string strRootURI = "https://exchangeserver/exchange/User1/Inbox/"; string strSPSRootURI = "https://wss/Shared%20Documents/"; string strUserName = "User1"; string strPassword = "Passw0rd"; string strDomain = "DOMAIN"; string strQuery =""; byte[] bytes = null; System.IO.Stream RequestStream = null; System.IO.Stream ResponseStream = null; XmlDocument ResponseXmlDoc = null; XmlNodeList ResponseNodes = null; XmlNamespaceManager xmlnsm = new XmlNamespaceManager(new NameTable()); xmlnsm.AddNamespace("a","DAV:"); try { // Build the SQL query. strQuery = "<?xml version=\"1.0\"?><D:searchrequest xmlns:D = \"DAV:\" >" + "<D:sql>SELECT \"DAV:displayname\" FROM \"" + strRootURI + "\"" + "WHERE \"DAV:ishidden\" = false AND \"DAV:isfolder\" = false" + "</D:sql></D:searchrequest>"; // Create a new CredentialCache object and fill it with the network // credentials required to access the server. MyCredentialCache = new System.Net.CredentialCache(); MyCredentialCache.Add( new System.Uri(strRootURI), "NTLM", new System.Net.NetworkCredential(strUserName, strPassword, strDomain) ); MyCredentialCache.Add(new System.Uri(strSPSRootURI), "NTLM", new System.Net.NetworkCredential(strUserName, strPassword, strDomain)); // Create the HttpWebRequest object. Request = (System.Net.HttpWebRequest)HttpWebRequest.Create(strRootURI); // Add the network credentials to the request. Request.Credentials = MyCredentialCache; // Specify the method. Request.Method = "SEARCH"; // Encode the body using UTF-8. bytes = Encoding.UTF8.GetBytes((string)strQuery); // Set the content header length. This must be // done before writing data to the request stream. Request.ContentLength = bytes.Length; //Set the translate header to false Request.Headers.Add("Translate","f"); // Get a reference to the request stream. RequestStream = Request.GetRequestStream(); // Write the SQL query to the request stream. RequestStream.Write(bytes, 0, bytes.Length); // Close the Stream object to release the connection // for further use. RequestStream.Close(); // Set the content type header. Request.ContentType = "text/xml"; // Send the SEARCH method request and get the // response from the server. Response = (HttpWebResponse)Request.GetResponse(); // Get the XML response stream. ResponseStream = Response.GetResponseStream(); // Create the XmlDocument object from the XML response stream. ResponseXmlDoc = new XmlDocument(); ResponseXmlDoc.Load(ResponseStream);
ResponseNodes = ResponseXmlDoc.GetElementsByTagName("a:response");
if(ResponseNodes.Count > 0)
{
Console.WriteLine("Non-folder item hrefs...");
// Loop through the display name nodes.
for(int i=0; i<ResponseNodes.Count; i++)
{
// Display the non-folder item displayname.
XmlNode responseNode = ResponseNodes[i];
XmlNode hrefNode = responseNode.SelectSingleNode("a:href",xmlnsm);
XmlNode displayNameNode = responseNode.SelectSingleNode("a:propstat/a:prop/a:displayname",xmlnsm);
//Downloads the EML file from the specified URL
byte[] emlFile = GetBytesFrom(hrefNode.InnerText);
//Uploads the EML file to the SharePoint document library
UploadToSPS(emlFile,strSPSRootURI + System.Web.HttpUtility.UrlPathEncode(displayNameNode.InnerText));
}
}
else
{
Console.WriteLine("No non-folder items found...");
}
// Clean up.
ResponseStream.Close();
Response.Close();
}
catch(Exception ex)
{
// Catch any exceptions. Any error codes from the SEARCH
// method request on the server will be caught here, also.
Console.WriteLine(ex.Message);
}
Console.WriteLine("Done.");
Console.Read();
}
static byte[] GetBytesFrom(string DavURL)
{
Console.WriteLine(DavURL);
byte[] buffer;
System.Net.HttpWebRequest Request;
System.Net.HttpWebResponse Response;
System.IO.Stream ResponseStream;
Request = (HttpWebRequest)HttpWebRequest.Create(DavURL);
Request.Credentials = MyCredentialCache;
Request.Headers.Add("Translate","f");
Response = (HttpWebResponse)Request.GetResponse();
ResponseStream = Response.GetResponseStream();
buffer = new byte[Response.ContentLength];
ResponseStream.Read(buffer,0,(int)Response.ContentLength);
ResponseStream.Close();
Response.Close();
return buffer;
}
static void UploadToSPS(byte[] fileBytes, string URL)
{
Console.WriteLine("Uploading " + fileBytes.Length.ToString() + " bytes to " + URL);
System.Net.HttpWebRequest Request;
Request = (HttpWebRequest)HttpWebRequest.Create(URL);
Request.Credentials = MyCredentialCache;
Request.ContentLength = fileBytes.Length;
Request.Method = "PUT";
System.IO.Stream str = Request.GetRequestStream();
str.Write(fileBytes,0,fileBytes.Length);
str.Close();
Request.GetResponse();
}
}
}
Comments
Anonymous
February 19, 2007
PingBack from http://mhinze.com/links-for-2007-02-08/Anonymous
March 05, 2007
Currently I can recieve but in eml format, will this fix so I recieve as email to open in my outlook client as a regular email. I need to have this work, we are intergrating the document library to our exchange 2007. I was told I needed a mapi client installed on the sharepoint 2007 server. But not sure if any special configuration is involved. Any help would be great.Anonymous
March 11, 2007
mmm.. nice design, I must say..Anonymous
March 13, 2007
The comment has been removedAnonymous
March 20, 2007
We implement a VERY similar technique, although we found you have to loop read the bytes as on larger emails stuff gets lost/truncated. See my blog entry for what I mean. http://nickwhite.spaces.live.com/blog/Anonymous
March 20, 2007
You will find you'll need to read the email stream in chunks to avoid loosing stuff and ending up with a truncated email (especially true when there are attachments, my blog has code for our very similar implementation.Anonymous
April 02, 2007
Hi Patrick, Good article. What I am trying to do is write an event handler for an email enabled document library. So, when my document library receives the eml file, I want to open the file and find out who the sender is, the subject, cc fields, body and what the attachments are. Do you know of any way to parse eml files through code? Thanks -pritamAnonymous
April 17, 2007
Hi Pritam. Yes, CDOSYS is an effective API for parsing eml files. http://msdn2.microsoft.com/en-us/library/ms527302.aspxAnonymous
September 19, 2007
I'm new to webDAV. How would you use this in a project?Anonymous
March 19, 2009
The comment has been removedAnonymous
March 25, 2009
Hi Saharathendral, Are you getting the red X where your image should be or are you just seeing a plain text email? If you are seeing the red X, then it is most likely that your images are stored in a location that requires authentication to access. You should put them somewhere they can be accessed anonymously. You'll also want to look at these articles: http://msdn.microsoft.com/en-us/library/aa338201.aspx http://msdn.microsoft.com/en-us/library/aa338200.aspx In Outlook 2003, there was an entirely different security mechanism in Tools/Options that governed how and if images were displayed in HTML emails. PatrickAnonymous
March 31, 2009
Hi Patrick, your reply helps us a lot to solve our problem. Thanks a lot. ;-) SaharathendralAnonymous
April 16, 2009
Hi Patrick! I'm not sure whether this is a good place to ask about this, so sorry if not, but here goes anyway. We have a "company-general" email address, that actually goes to just one person's mailbox. Currently the person then forwards the messages to whoever he guesses the message concerns. We would like to have the messages sent to this address be somehow automatically moved to a place in Sharepoint where other people could see them if they like and put alerts to get notification etc. Ideally this place could be a Sharepoint discussion forum so that the messages could be seen similar to as in an email reader. We could of course just forward the mails coming to the address to all those who want to receive them, but then the decision of whether to receive them or not would be more of an on-off decision, all or nothing. If the messages (even only text body would be enough) would automatically appear on a Sharepoint page, then the people could check them when they want (for example when they expect something concerning them to be inbound) and then ignore them in other times. Finally, in our location we don't have the Sharepoint server, it is managed by IT in another location so it would be best if something like this could be done without any actual extra coding, just utilizing existing features, adding a suitable web part or something similar. Do you think anything like this would be reasonably easily doable? -AnttiAnonymous
April 23, 2009
The comment has been removedAnonymous
April 23, 2009
The comment has been removedAnonymous
July 22, 2009
Hi Roopesh, It looks like your value for strRootURI is incorrect - it should be directed at the mailbox you intend to log on to - not the logon page for owa. There are strategies you can employ to get the auth cookie from OWA and include it in your requests (http://support.microsoft.com/kb/891748/), but my sample above assumes OWA is configured for Basic or Windows authentication, not Forms Based Authentication.Anonymous
July 28, 2009
I got a hold of Exchange email body (in html) through Exchange Impersonation. How do I convert it to plain text?Anonymous
August 28, 2009
How did you get the html? (There may be a similar way to get the plain text.)Anonymous
October 21, 2009
just use discussion board as a library which creates a body field so you don't need to worry about reading eml file body.