HOWTO: Get Email Messages from Exchange to SharePoint

Published 06 February 07 11:15 AM

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 = "http://exchangeserver/exchange/User1/Inbox/"; 
            string strSPSRootURI = "http://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(); 
        } 
    }
}

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

# mhinze.com » Blog Archive » links for 2007-02-08 said on February 19, 2007 9:03 AM:

PingBack from http://mhinze.com/links-for-2007-02-08/

# scoleman said on March 5, 2007 1:39 PM:

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.

# ... said on March 12, 2007 6:03 AM:

mmm.. nice design, I must say..

# Patrick Creehan said on March 13, 2007 1:14 PM:

So the reason you need a MAPI client is that Outlook is a MAPI client and reads MAPI data from a MAPI store. MSG is the file format for MAPI data. These types of files would open in Outlook. It would involve a completely different code path to get the MAPI data from the store and save it as MSG. You can use MAPI Editor's source code available from this KB article (http://support.microsoft.com/kb/291794/) to do so. However, please note that MAPI code is not supported inline with .NET code. You would have to do this in C++ unmanaged code and wrap it in a COM+ component that you could call into from .NET. Outlook Object Model can also save messages as MSG files, but be careful again because Outlooks OMG (Object Model Guard) can prompt you with security prompts. Once you save the msg file to the disk, you can use the same UploadToSPS code I have above to push it into SharePoint. The reason I went after the EML (MIME content) files is that WebDAV is supported under .NET.

# Nick said on March 20, 2007 11:00 AM:

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/

# Nick said on March 20, 2007 11:31 AM:

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.

# Pritam said on April 2, 2007 4:05 PM:

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

-pritam

# Patrick Creehan said on April 17, 2007 9:21 AM:

Hi Pritam. Yes, CDOSYS is an effective API for parsing eml files.

http://msdn2.microsoft.com/en-us/library/ms527302.aspx

# DLS said on September 19, 2007 11:46 PM:

I'm new to webDAV. How would you use this in a project?

# Saharathendral said on March 20, 2009 12:51 AM:

Hi Patrick Creehan,

I am also working in SharePoint 2007. I am facing some problem with images while sending it thru mail. Our problem is, we are sending Emails (watch word - with image) to end users on daily basis. Currently we are doing it manually. Now we need to automate this using SharePoint designer work flow. The problem is background images are not displayed while getting the emails in outlook. There is no problem with the text. We are in hot stove now. Could you please help me to solve this?

Thanks.

Saharathendral

# Patrick Creehan said on March 25, 2009 10:26 AM:

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.

Patrick

# Saharathendral said on April 1, 2009 7:02 AM:

Hi Patrick,

your reply helps us a lot to solve our problem. Thanks a lot. ;-)

Saharathendral

Leave a Comment

(required) 
(optional)
(required) 

About Patrick Creehan

Patrick Creehan is an Escalation Engineer in the Office Messaging Development team at Microsoft.
Page view tracker