Read MS Exchange email in C#
Asked Answered
T

8

93

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

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

Toxicity answered 16/3, 2009 at 23:34 Comment(2)
Microsoft has since released Exchange Web Services Managed API for Exchange 2007 SP1 and v2010 which allows one to programatically get into your mailbox without the need for Outlook. I have two articles on my blog which discuss this approach: - C#: Getting All Emails From Exchange using Exchange Web ServicesUtopian
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. msdn.microsoft.com/en-us/library/dd633710(EXCHG.80).aspxDearing
O
91

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.

Ocular answered 17/3, 2009 at 0:30 Comment(2)
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: msdn.microsoft.com/en-us/library/dd633710(EXCHG.80).aspxDearing
It's almost as if Microsoft designed it to be inoperable with anything but OutlookNor
A
72

Um,

I might be a bit too late here but isn't this kinda the point to EWS ?

https://msdn.microsoft.com/en-us/library/dd633710(EXCHG.80).aspx

Takes about 6 lines of code to get the mail from a mailbox:

ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2007_SP1);

//service.Credentials = new NetworkCredential( "{Active Directory ID}", "{Password}", "{Domain Name}" );

service.AutodiscoverUrl( "[email protected]" );

FindItemsResults<Item> findResults = service.FindItems(
   WellKnownFolderName.Inbox,
   new ItemView( 10 ) 
);

foreach ( Item item in findResults.Items )
{
   Console.WriteLine( item.Subject );
}
Apo answered 8/7, 2011 at 9:5 Comment(6)
"The EWS Managed API simplifies the implementation of applications that communicate with Microsoft Exchange Server 2007 Service Pack 1 (SP1) and later versions of Microsoft Exchange"Nor
Realize this is essentially a necrobump for a years-old message, but this code had me up and running for a similar project in about five minutes. Worked perfectly the first time through. Really a more contemporary/comprehensive solution than the selected answer IMO...noting for anyone else's reference.Shill
Note on getting this running. You need to install the NuGet package "Microsoft Exchange WebServices"Ilex
This worked for me on the first try. This should be the new accepted answer.Godbeare
May I know if I were to use an email address apart from my own mailbox in service.autodiscoverurl, i will need to enter the service.credentials, am I right?Adriatic
usually yes .. unless you're doing something odd on the domain exchange servers would typically ask for the credentials to the mailbox you're trying to access.Apo
C
22
  1. Graph - currently, the preferred unified API (pure HTTP based) to access emails, contacts, appointments, tasks etc., residing on Exchange Server along with other data hosted by Microsoft (Teams, Sharepoint, etc.).
    Use Graph Explorer or OutlookSpy (I am its author) to play with the API.
    Microsoft provides Graph SDK for use in several languages

  2. EWS. Fully supported. It is purely HTTP based and can be accessed from any language, but there are .Net and Java specific libraries.
    MS has indicated that no new features will be added, and that Graph is preferable, even though not all EWS features are yet available in Graph (such as high fidelity Fast Transfer Stream export/import exposed through ExportItems/ImportItems).
    You can use EWSEditor or OutlookSpy (I am its author) to play with the API.

  3. Extended MAPI. This is the native API used by Outlook. It ends up using the MSEMS Exchange MAPI provider, which can talk to Exchange using RPC (Exchange 2013 no longer supports it) or RPC-over-HTTP (Exchange 2007 or newer) or MAPI-over-HTTP (Exchange 2013 and newer).
    The API itself can only be accessed from unmanaged C++ or Delphi. You can also use Redemption (any language, I am its author) - its RDO family of objects is an Extended MAPI wrapper. To use Extended MAPI, you need to install either Outlook or the standalone (Exchange) version of MAPI (on extended support, and it does not support Unicode PST and MSG files and cannot access Exchange 2016). Extended MAPI can be used in a service.
    You can play with the API using OutlookSpy (I am its author) or MFCMAPI.

  4. Outlook Object Model - not Exchange specific, but it allows access to all data available in Outlook on the machine where the code runs. Cannot be used in a service.

  5. Exchange Active Sync. Microsoft no longer invests any significant resources into this protocol.

  6. Outlook used to install CDO 1.21 library (it wraps Extended MAPI), but it had been deprecated by Microsoft and no longer receives any updates.

  7. There used to be a third-party .Net MAPI wrapper called MAPI33, but it is no longer being developed or supported.

  8. WebDAV - deprecated.

  9. Collaborative Data Objects for Exchange (CDOEX) - deprecated.

  10. Exchange OLE DB Provider (EXOLEDB) - deprecated.

Cr answered 17/3, 2016 at 18:26 Comment(1)
the EwsEditor has moved to github: github.com/dseph/EwsEditorAnnora
L
11

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; }
    }
}
Lux answered 17/3, 2009 at 1:20 Comment(1)
NOTE: WebDAV support is dropped from Exchange Server 2010, use EWS instead.Gallicism
L
1

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.

Livingston answered 17/3, 2009 at 0:3 Comment(0)
C
0

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.

Coben answered 16/3, 2009 at 23:50 Comment(0)
D
0

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: Download location for MAPI33.dll?

Darrel answered 17/3, 2009 at 0:1 Comment(0)
B
0

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

Baum answered 17/3, 2009 at 1:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.