HOWTO: Get Email Messages from Exchange to SharePoint

HOWTO: Get Email Messages from Exchange to SharePoint

  • Comments 19

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

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

  • 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.

  • mmm.. nice design, I must say..

  • 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.

  • 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/

  • 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.

  • 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

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

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

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

  • 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

  • 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

  • Hi Patrick,

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

    Saharathendral

  • 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?

    -Antti

  • I am getting the remote server returned an error 403 forbidden after it reach this line

                // Send the SEARCH method request and get the

                   // response from the server.

                   Response = (HttpWebResponse)Request.GetResponse();

  • I am getting a 403 error here on this line

    // Get a reference to the request stream.

                   RequestStream = Request.GetRequestStream();

    I have a https URI web email access

    string strRootURI = "https://webmail.hhs.gov/exchweb/bin/auth/owalogon.asp?url=https://webmail.hhs.gov/exchange&reason=0";

               string strSPSRootURI = "http://samhsa-dmsg:48497/Email%20Import/";

Page 1 of 2 (19 items) 12