none
Retrieve Email Attachments from Exchange 2003 RRS feed

  • Question

  • I need to retrieve email attachments from a mailbox on an exchange server. Its exchange 2003 so don't have the option of using Exchange Web Services (which would make this a lot easier!).

    Ideally looking to do this in a .net console app, which I can then expose as a service.

    Some of the API libraries available are out of the question for security reasons as we are not allowed to just download additional libraries without them being tested.

    Is it possible to use WebDav / MAPI with the standard .net framework? I have already posted in .net forum and been told to post in here.

    Any suggestions / advice / code examples greatly appreciated.

    Friday, April 8, 2011 8:59 AM

Answers

  • Yes, the search request won't return a list of attachments for each item in the set of results, so you have to do some iteration.  Each item in the list will contain the URL for each message, and you send an X-MS-ENUMATTS to each URL to get a list of attachment URLs.

    I've never saved an attachment to disk, but I imagine that the ADO Stream object has the required methods (i.e. write to the stream from the GET ResponseBody, and then save the stream to a file):

    http://msdn.microsoft.com/en-us/library/ms675032(v=vs.85).aspx


    Outlook Web Access For PDA , OWA For WAP
    www.owa-pda.com
    email a@t leederbyshire d.0.t c.0.m
    • Marked as answer by suggy1982 Monday, May 9, 2011 3:31 PM
    Wednesday, April 13, 2011 2:22 PM

All replies

  • You don't need to use WebDAV as such, since a simple GET to the attachment URL is sufficient to retrieve it.  I don't know about MAPI.  Have you got anywhere with this yet?  Do you know how to get the attachment URLs?
    Outlook Web Access For PDA , OWA For WAP
    www.owa-pda.com
    email a@t leederbyshire d.0.t c.0.m
    Friday, April 8, 2011 2:03 PM
  • Do you know how to get the attachment URLs?

    Thanks for the reply.

    I am affraid I don't know how to get the attachments URLs. I haven't done any development with Exchange before.

    Friday, April 8, 2011 2:37 PM
  • Okay.  I think it'll be easier (both to read, and to tackle) if I break it into steps.

    1. Send a WebDAV PROPFIND to the mailbox URL (should be easy to guess, it's usually http://server/exchange/user@domain.com , or you may need to use https, if you require SSL on your OWA) to get the Inbox URL (assuming you're only interested in the Inbox, otherwise you'll need to get a list of folder URLs, instead).  The Inbox URL is nearly always http://server/exchange/user@domain.com/inbox (or you may need https again).
    2. Send a SEARCH request to the Inbox URL to get a list of message URLs.
    3. Send an X-MS-ENUMATTS request to each message URL to get a list of attachment URLs for each message.  If there are none, you can move to the next message.
    4. Send a GET to each attachment URL to get the attachment.

    That's a rather brief way of describing a lot of work, but if you're able to follow it, it will be quicker than me going into more detail at this stage.  If you still don't know where to start, let me know; but right now, I've no way of telling how much you'll be able to do for yourself.  If you use Forms-based Auth on your OWA, it complicates things, but there are articles explaining how to negotiate your requests through it.


    Outlook Web Access For PDA , OWA For WAP
    www.owa-pda.com
    email a@t leederbyshire d.0.t c.0.m
    Friday, April 8, 2011 2:55 PM
  • Hello,

    Thanks for getting back to me. I seem to be getting somewhere now.

    I have done any development work with WebDav before so you might have to bear with me.

    http://blogs.msdn.com/b/webdav_101/archive/2008/03/12/howto-webdav-propfind-using-vb-net.aspx and http://msdn.microsoft.com/en-us/library/aa142960(v=exchg.65).aspx

    So I sort of get hte idea, but if you can talk me through this in a little more detail I would appreciate it. Happy to discuss on Windows Messenger at a time to suit you if it helps.

    Thanks again.

    Friday, April 8, 2011 3:47 PM
  • No problem.  But I only use VB.Net in .aspx , so I'd have to learn a few things myself before I could start you off in whatever development environment you are using.  Try something like this, and explore the menu on the left:

    http://msdn.microsoft.com/en-us/library/Aa123571

    When you're comfortable doing some basic WebDAV things in your environment, I can offer some more specific help.

    Believe it or not, I don't use Windows Messenger, or any other form of instant messaging (or even Facebook or Twitter - I don't have the time).


    Outlook Web Access For PDA , OWA For WAP
    www.owa-pda.com
    email a@t leederbyshire d.0.t c.0.m
    Friday, April 8, 2011 10:56 PM
  • Thanks for you reply again Lee. Looking on MSDN and the following like http://www.codeproject.com/KB/cs/Exchange_2003_with_WebDav.aspx I have an understanding now of how WebDav works and how to us it.

    I suppose I just have 2 outstanding questions for what I am trying to achieve. I assume once you receive a response to a SEARCH request you can iterate/loop through the result to then call additional methods for each email in the results list (like calling a GET method).

    And finally, once you call a GET on an attachment, how do you then write this out to a file on your HD or network?

    Thanks for your help.

    Adrian

    Wednesday, April 13, 2011 2:09 PM
  • Yes, the search request won't return a list of attachments for each item in the set of results, so you have to do some iteration.  Each item in the list will contain the URL for each message, and you send an X-MS-ENUMATTS to each URL to get a list of attachment URLs.

    I've never saved an attachment to disk, but I imagine that the ADO Stream object has the required methods (i.e. write to the stream from the GET ResponseBody, and then save the stream to a file):

    http://msdn.microsoft.com/en-us/library/ms675032(v=vs.85).aspx


    Outlook Web Access For PDA , OWA For WAP
    www.owa-pda.com
    email a@t leederbyshire d.0.t c.0.m
    • Marked as answer by suggy1982 Monday, May 9, 2011 3:31 PM
    Wednesday, April 13, 2011 2:22 PM
  • Thanks for your help on this. I have made alot of progress since your last post.

    The only issue I am having now is that when I send an email to myself with an attachment to test the code, the program is hanging on the GET call. But it works fine for emails with attachments that are already in my inbox.

    Do you happen to know if there is some delay in new emails/attachments being posted to the exchange data store?

    Thanks,

    Adrian

    Monday, May 9, 2011 2:21 PM
  • There shouldn't be any noticeable delay, as far as I know, but obviously everything takes time - even if it's just a fraction of a second.  What I mean is, if you are adding the attachment, and then trying to GET it immediately afterwards, there may be an issue.  But if you are sending yourself an attachment in, say, Outlook; and then a few seconds later running your GET code, then there shouldn't normally be a problem.

    I think it would be useful to do some tests to see if the attachments that fail the GET do eventually become reachable after a longer period of time.


    Outlook Web Access For PDA , OWA For WAP
    www.owa-pda.com
    email a@t leederbyshire d.0.t c.0.m
    Monday, May 9, 2011 2:30 PM
  • I have waited over an hour since sending the email and although I can see it in my inbox in Outlook I can get the attachment to download via WebDav. I am going to leave it over night and see if it comes through tomorrow. but I just wondered if you knew of any processes that might be running on exchange which would impact this.
    Monday, May 9, 2011 3:15 PM
  • I'm afraid that I don't know of any reason why it should not work straight away.  It always has for me.  I'll keep an eye on your new post regarding this issue, but I'll leave it alone for now.
    Outlook Web Access For PDA , OWA For WAP
    www.owa-pda.com
    email a@t leederbyshire d.0.t c.0.m
    Monday, May 9, 2011 3:33 PM
  • I have run the program again this morning and it is still failing to pick up the attachment. Would you mind reviewing my code? It seems to be failing on the XmlHttp40.send() in the extractattachment method. I have some code before this which gets a list of emails from the mailbox. But I didn't include this because it seems to be working fine.

        #region ProcessEmail
        private static void ProcessEmail(System.Xml.XmlNode Node)
        {
          MSXML2.ServerXMLHTTP40 XmlHttp40 = new MSXML2.ServerXMLHTTP40();
          System.Xml.XmlDataDocument XmlDDoc = new System.Xml.XmlDataDocument();
          XmlNodeList XmlNodeList = null;
          XmlNodeList XmlAttachmentNameList = null;
          System.Xml.XmlNode XmlAttachmentNode = null;
          System.Xml.XmlNode XmlAttachmentNameNode = null;
          string ResponseText = "";
          int iNode = 0;
    
          // request email attachment properties
    
          XmlHttp40.open("X-MS-ENUMATTS", Node.InnerText, false, ConfigurationManager.AppSettings["UserName"].ToString(), ConfigurationManager.AppSettings["Password"].ToString());
    
          XmlHttp40.setRequestHeader("Depth", "1");
    
          XmlHttp40.setRequestHeader("Content-type", "xml");
    
          XmlHttp40.send();
    
          // Store the data and open it in an xml document object.
    
          ResponseText = XmlHttp40.responseText;
    
          XmlDDoc.LoadXml(ResponseText);
    
          // Get a list of attachment nodes.
    
          XmlNodeList = XmlDDoc.GetElementsByTagName("a:href");
    
          XmlAttachmentNameList = XmlDDoc.GetElementsByTagName("e:attachmentfilename");
    
          // Loop through the nodes and process each email.
    
          for (iNode = XmlNodeList.Count - 1; iNode >= 0; iNode += -1)
          {
            XmlAttachmentNode = XmlNodeList.Item(iNode);
    
            XmlAttachmentNameNode = XmlAttachmentNameList.Item(iNode);
    
            log.Info(string.Format("Processing Attachment: {0}, Attachment Name: {1}", XmlAttachmentNode.InnerText, XmlAttachmentNameNode.InnerText));
            ExtractAttachment(XmlAttachmentNode, XmlAttachmentNameNode);
          }
        }
        #endregion
    
        #region ExtractAttachment
        private static void ExtractAttachment(System.Xml.XmlNode Node, System.Xml.XmlNode FileNameNode)
        {
          MSXML2.XMLHTTP40 XmlHttp40 = new MSXML2.XMLHTTP40();
          string strPath = "";
    
          // Get attachment from exchange
    
          XmlHttp40.open("GET", Node.InnerText, false, ConfigurationManager.AppSettings["UserName"].ToString(), ConfigurationManager.AppSettings["Password"].ToString());
    
          XmlHttp40.send();
    
          byte[] ResponseBody = (byte[])XmlHttp40.responseBody;
    
          // Only process actual attachments...ignore embedded images
    
          if (FileNameNode != null)
          {
    
            // create custom filename to avoid replacing existing files.
    
            string strFileName = DateTime.Now.ToString("yyyyMMdd") + "_" + m_count + "_" + FileNameNode.InnerText;
    
            // Determine file path to extract to.
    
            switch (Path.GetExtension(strFileName).ToUpper())
            {
              case ".DOC":
                strPath = Path.Combine(Properties.Settings.Default.ExtractionDirectory_AP, strFileName);
                break;
              case ".XLS":
                strPath = Path.Combine(Properties.Settings.Default.ExtractionDirectory_Data, strFileName);
                break;
              default:
                strPath = "";
                break;
            }
    
            if (strPath != "")
            {
    
              // Extract attachment
    
              File.WriteAllBytes(strPath, ResponseBody);
              log.Info(string.Format("File created: {0}", strPath));
              m_count += 1;
            }
          }
        }
        #endregion
    
    Tuesday, May 10, 2011 6:39 AM
  • This only seems to be happening with Office files (word, excel) and I have got office 2007 installed on my PC. If i create a brand new .txt file and send that to myself it extracts fine.

    Tuesday, May 10, 2011 7:03 AM
  • I'm not familiar with the language you are using, but are you using the filename to build the URL for your GET, rather than the attachment's URL?  The filename would not be correctly URL-encoded (unless it was very simple, without spaces, etc.).  It would help to see the iis log entries for the GETs.


    Outlook Web Access For PDA , OWA For WAP
    www.owa-pda.com
    email a@t leederbyshire d.0.t c.0.m
    Tuesday, May 10, 2011 7:37 AM
  • I am using c#.net. I am using the a:href to get the attachment. the attachmentfilename is only for saving the file to disk.

    This is what the URL for the attachment looks like in my code

    HTTP://../Inbox/Test/Emailing:%20Test.docx.EML/Test.docx

    I have narrowed down the problem further. if I send .xlsx or docx file to myself they extract fine. But .xls or .doc files don't. But if I rename a .xls file to .fred for example it extracts fine. very weird.

    Tuesday, May 10, 2011 7:56 AM
  • Sorted, I was using a MSXML2.XMLHTTP40 object instead of a MSXML2.ServerXMLHTTP40 object to send my request.

    I have changed this now and it is working fine.

    Tuesday, May 10, 2011 10:20 AM
  • I've no idea why that would make a difference, but I'm glad you got it sorted.
    Outlook Web Access For PDA , OWA For WAP
    www.owa-pda.com
    email a@t leederbyshire d.0.t c.0.m
    Tuesday, May 10, 2011 10:38 AM