views:

16678

answers:

8

I need the ability to monitor for and read email from a particular mailbox on a MS Exchange Server (internal to my company). I also need to be able to read the sender's email address, subject, message body and download an attachment if any.

What is the best way to do this using C# (or Vb.net)?

A: 

If your Exchange server is configured to support POP or IMAP, that's an easy way out.

Another option is WebDAV access. there is a library available for that. This might be your best option.

I think there are options using COM objects to access Exchange, but I'm not sure how easy it is.

It all depends on what exactly your administrator is willing to give you access to I guess.

Denis Troller
A: 

You should be able to use MAPI to access the mailbox and get the information you need. Unfortunately the only .NET MAPI library (MAPI33) I know of seems to be unmaintained. This used to be a great way to access MAPI through .NET, but I can't speak to its effectiveness now. There's more information about where you can get it here: http://stackoverflow.com/questions/362359/download-location-for-mapi33dll

Chris Hynes
A: 

I used code that was published on CodeProject.com. If you want to use POP3, it is one of the better solutions that I have found.

Eldila
+27  A: 

It's a mess. MAPI or CDO via a .NET interop DLL is officially unsupported by Microsoft--it will appear to work fine, but there are problems with memory leaks due to their differing memory models. You could use CDOEX, but that only works on the Exchange server itself, not remotely; useless. You could interop with Outlook, but now you've just made a dependency on Outlook; overkill. Finally, you could use Exchange 2003's WebDAV support, but WebDAV is complicated, .NET has poor built-in support for it, and (to add insult to injury) Exchange 2007 nearly completely drops WebDAV support.

What's a guy to do? I ended up using AfterLogic's IMAP component to communicate with my Exchange 2003 server via IMAP, and this ended up working very well. (I normally seek out free or open-source libraries, but I found all of the .NET ones wanting--especially when it comes to some of the quirks of 2003's IMAP implementation--and this one was cheap enough and worked on the first try. I know there are others out there.)

If your organization is on Exchange 2007, however, you're in luck. Exchange 2007 comes with a SOAP-based Web service interface that finally provides a unified, language-independent way of interacting with the Exchange server. If you can make 2007+ a requirement, this is definitely the way to go. (Sadly for me, my company has a "but 2003 isn't broken" policy.)

If you need to bridge both Exchange 2003 and 2007, IMAP or POP3 is definitely the way to go.

Nicholas Piasecki
The SOAP-based web service was wrapped by Microsoft to simplify access - it is now recommended practice to use the Exchange Web Services Managed API 1.0 SDK:http://msdn.microsoft.com/en-us/library/dd633710(EXCHG.80).aspx
jlo
A: 

I got a solution working in the end using Redemption, have a look at these questions...

Paul Rowland
+2  A: 

Here is some old code I had laying around to do WebDAV. I think it was written against Exchange 2003, but I don't remember any more. Feel free to borrow it if its helpful...

class MailUtil
{
    private CredentialCache creds = new CredentialCache();

    public MailUtil()
    {
        // set up webdav connection to exchange
        this.creds = new CredentialCache();
        this.creds.Add(new Uri("http://mail.domain.com/Exchange/[email protected]/Inbox/"), "Basic", new NetworkCredential("myUserName", "myPassword", "WINDOWSDOMAIN"));
    }

    /// <summary>
    /// Gets all unread emails in a user's Inbox
    /// </summary>
    /// <returns>A list of unread mail messages</returns>
    public List<model.Mail> GetUnreadMail()
    {
        List<model.Mail> unreadMail = new List<model.Mail>();

        string reqStr =
            @"<?xml version=""1.0""?>
                <g:searchrequest xmlns:g=""DAV:"">
                    <g:sql>
                        SELECT
                            ""urn:schemas:mailheader:from"", ""urn:schemas:httpmail:textdescription""
                        FROM
                            ""http://mail.domain.com/Exchange/[email protected]/Inbox/"" 
                        WHERE 
                            ""urn:schemas:httpmail:read"" = FALSE 
                            AND ""urn:schemas:httpmail:subject"" = 'tbintg' 
                            AND ""DAV:contentclass"" = 'urn:content-classes:message' 
                        </g:sql>
                </g:searchrequest>";

        byte[] reqBytes = Encoding.UTF8.GetBytes(reqStr);

        // set up web request
        HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create("http://mail.domain.com/Exchange/[email protected]/Inbox/");
        request.Credentials = this.creds;
        request.Method = "SEARCH";
        request.ContentLength = reqBytes.Length;
        request.ContentType = "text/xml";
        request.Timeout = 300000;

        using (Stream requestStream = request.GetRequestStream())
        {
            try
            {
                requestStream.Write(reqBytes, 0, reqBytes.Length);
            }
            catch
            {
            }
            finally
            {
                requestStream.Close();
            }
        }

        HttpWebResponse response = (HttpWebResponse)request.GetResponse();
        using (Stream responseStream = response.GetResponseStream())
        {
            try
            {
                XmlDocument document = new XmlDocument();
                document.Load(responseStream);

                // set up namespaces
                XmlNamespaceManager nsmgr = new XmlNamespaceManager(document.NameTable);
                nsmgr.AddNamespace("a", "DAV:");
                nsmgr.AddNamespace("b", "urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/");
                nsmgr.AddNamespace("c", "xml:");
                nsmgr.AddNamespace("d", "urn:schemas:mailheader:");
                nsmgr.AddNamespace("e", "urn:schemas:httpmail:");

                // Load each response (each mail item) into an object
                XmlNodeList responseNodes = document.GetElementsByTagName("a:response");
                foreach (XmlNode responseNode in responseNodes)
                {
                    // get the <propstat> node that contains valid HTTP responses
                    XmlNode uriNode = responseNode.SelectSingleNode("child::a:href", nsmgr);
                    XmlNode propstatNode = responseNode.SelectSingleNode("descendant::a:propstat[a:status='HTTP/1.1 200 OK']", nsmgr);
                    if (propstatNode != null)
                    {
                        // read properties of this response, and load into a data object
                        XmlNode fromNode = propstatNode.SelectSingleNode("descendant::d:from", nsmgr);
                        XmlNode descNode = propstatNode.SelectSingleNode("descendant::e:textdescription", nsmgr);

                        // make new data object
                        model.Mail mail = new model.Mail();
                        if (uriNode != null)
                            mail.Uri = uriNode.InnerText;
                        if (fromNode != null)
                            mail.From = fromNode.InnerText;
                        if (descNode != null)
                            mail.Body = descNode.InnerText;
                        unreadMail.Add(mail);
                    }
                }

            }
            catch (Exception e)
            {
                string msg = e.Message;
            }
            finally
            {
                responseStream.Close();
            }
        }

        return unreadMail;
    }
}

And model.Mail:

class Mail
{
    private string uri;
    private string from;
    private string body;

    public string Uri
    {
        get { return this.uri; }
        set { this.uri = value; }
    }

    public string From
    {
        get { return this.from; }
        set { this.from = value; }
    }

    public string Body
    {
        get { return this.body; }
        set { this.body = value; }
    }
}
rally25rs
A: 

One option is to use Outlook. We have a mail manager application that access an exchange server and uses outlook as the interface. Its dirty but it works.

Example code:

public Outlook.MAPIFolder getInbox()
     {
      mailSession = new Outlook.Application();
      mailNamespace = mailSession.GetNamespace("MAPI");
      mailNamespace.Logon(mail_username, mail_password, false, true);
      return MailNamespace.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox);
     }
duncane
+2  A: 

Microsoft has since released Exchange Web Services Managed API] which allows one to pro grammatically without Outlook mind you access a target mailbox. I have two articles on my blog which discuss

OmegaMan
The Exchange Web Services Managed API 1.0 SDK is the Microsoft Recommended method for updating Exchange programatically for Exchange Server 2007 SP1 and above.http://msdn.microsoft.com/en-us/library/dd633710(EXCHG.80).aspx
jlo