Lire les e-mails MS Exchange en C #


90

J'ai besoin de la capacité de surveiller et de lire le courrier électronique d'une boîte aux lettres particulière sur un serveur MS Exchange (interne à mon entreprise). Je dois également être capable de lire l'adresse e-mail de l'expéditeur, l'objet, le corps du message et de télécharger une pièce jointe, le cas échéant.

Quelle est la meilleure façon de procéder en utilisant C # (ou VB.NET)?


4
Microsoft a depuis publié l'API gérée des services Web Exchange pour Exchange 2007 SP1 et v2010, qui permet d'accéder par programme à votre boîte aux lettres sans avoir besoin d'Outlook. J'ai deux articles sur mon blog qui traitent de cette approche: - C #: Obtenir tous les e-mails d'Exchange à l'aide des services Web Exchange
ΩmegaMan

Le Kit de développement logiciel (SDK) de l'API 1.0 gérée des services Web Exchange est la méthode recommandée par Microsoft pour mettre à jour Exchange par programme pour Exchange Server 2007 SP1 et les versions ultérieures. msdn.microsoft.com/en-us/library/dd633710(EXCHG.80).aspx
jlo

Réponses:


90

C'est le bordel. MAPI ou CDO via une DLL d'interopérabilité .NET n'est officiellement pas pris en charge par Microsoft - cela semble fonctionner correctement, mais il existe des problèmes de fuites de mémoire en raison de leurs modèles de mémoire différents. Vous pouvez utiliser CDOEX, mais cela ne fonctionne que sur le serveur Exchange lui-même, pas à distance; inutile. Vous pouvez interopérer avec Outlook, mais vous venez de créer une dépendance à Outlook; exagéré. Enfin, vous pouvez utiliser la prise en charge de WebDAV d'Exchange 2003 , mais WebDAV est compliqué, .NET a une prise en charge intégrée médiocre et (pour ajouter l'insulte à la blessure) Exchange 2007 abandonne presque complètement la prise en charge de WebDAV.

Qu'est-ce qu'un gars à faire? J'ai fini par utiliser le composant IMAP d'AfterLogic pour communiquer avec mon serveur Exchange 2003 via IMAP, et cela a très bien fonctionné. (Je recherche normalement des bibliothèques gratuites ou open-source, mais j'ai trouvé que toutes les bibliothèques .NET voulaient - en particulier en ce qui concerne certaines des bizarreries de l'implémentation IMAP de 2003 - et celle-ci était assez bon marché et fonctionnait sur la première essayez. Je sais qu'il y en a d'autres là-bas.)

Cependant, si votre organisation utilise Exchange 2007, vous avez de la chance. Exchange 2007 est fourni avec une interface de service Web basée sur SOAP qui offre enfin une manière unifiée et indépendante de la langue d'interagir avec le serveur Exchange. Si vous pouvez faire de 2007+ une exigence, c'est certainement la voie à suivre. (Malheureusement pour moi, mon entreprise a une politique "mais 2003 n'est pas rompu".)

Si vous avez besoin de relier à la fois Exchange 2003 et 2007, IMAP ou POP3 est certainement la voie à suivre.


21
Le service Web basé sur SOAP a été encapsulé par Microsoft pour simplifier l'accès - il est maintenant recommandé d'utiliser le SDK de l'API 1.0 gérée des services Web Exchange: msdn.microsoft.com/en-us/library/dd633710(EXCHG.80).aspx
jlo

4
C'est presque comme si Microsoft l'avait conçu pour être inopérant avec tout sauf Outlook
Chris S

67

Hum,

Je suis peut-être un peu trop tard ici, mais n'est-ce pas le but d'EWS?

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

Prend environ 6 lignes de code pour obtenir le courrier d'une boîte aux lettres:

ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2007_SP1);

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

service.AutodiscoverUrl( "First.Last@MyCompany.com" );

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

foreach ( Item item in findResults.Items )
{
   Console.WriteLine( item.Subject );
}

5
«L'API managée EWS simplifie la mise en œuvre des applications qui communiquent avec Microsoft Exchange Server 2007 Service Pack 1 (SP1) et les versions ultérieures de Microsoft Exchange»
Chris S

2
Réalisez que c'est essentiellement une nécrobompe pour un message vieux de plusieurs années, mais ce code m'a permis de démarrer un projet similaire en environ cinq minutes. A parfaitement fonctionné la première fois. Vraiment une solution plus contemporaine / complète que la réponse choisie IMO ... notant pour la référence de quelqu'un d'autre.
David W

2
Remarque sur la mise en marche de ce. Vous devez installer le package NuGet «Microsoft Exchange WebServices»
John M

4
Cela a fonctionné pour moi du premier coup. Cela devrait être la nouvelle réponse acceptée.
kroe761

Puis-je savoir si je devais utiliser une adresse e-mail en dehors de ma propre boîte aux lettres service.autodiscoverurl, je devrai entrer le service.credentials, ai-je raison?
gymcode

19
  1. L'API actuellement préférée (Exchange 2013 et 2016) est EWS . Il est purement basé sur HTTP et peut être consulté à partir de n'importe quel langage, mais il existe des bibliothèques spécifiques .Net et Java .

    Vous pouvez utiliser EWSEditor pour jouer avec l'API.

  2. MAPI étendu . Il s'agit de l'API native utilisée par Outlook. Il finit par utiliser le MSEMSfournisseur Exchange MAPI, qui peut parler à Exchange en utilisant RPC (Exchange 2013 ne le prend plus en charge) ou RPC-sur-HTTP (Exchange 2007 ou plus récent) ou MAPI-sur-HTTP (Exchange 2013 et plus récent).

    L'API elle-même n'est accessible qu'à partir de C ++ ou Delphi non managé . Vous pouvez également utiliser Redemption (n'importe quel langage) - sa famille d'objets RDO est un wrapper MAPI étendu. Pour utiliser Extended MAPI, vous devez installer Outlook ou la version autonome (Exchange) de MAPI (sur support étendu, et il ne prend pas en charge les fichiers Unicode PST et MSG et ne peut pas accéder à Exchange 2016). Le MAPI étendu peut être utilisé dans un service.

    Vous pouvez jouer avec l'API en utilisant OutlookSpy ou MFCMAPI .

  3. Modèle d'objet Outlook - pas spécifique à Exchange, mais il permet d'accéder à toutes les données disponibles dans Outlook sur la machine sur laquelle le code s'exécute. Ne peut pas être utilisé dans un service.

  4. Exchange Active Sync . Microsoft n'investit plus de ressources significatives dans ce protocole.

  5. Outlook avait l'habitude d'installer la bibliothèque CDO 1.21 (il encapsule le MAPI étendu), mais il était obsolète par Microsoft et ne reçoit plus de mises à jour.

  6. Il y avait autrefois un wrapper .Net MAPI tiers appelé MAPI33, mais il n'est plus développé ou pris en charge.

  7. WebDAV - obsolète.

  8. Objets de données collaboratifs pour Exchange (CDOEX) - obsolète.

  9. Fournisseur Exchange OLE DB (EXOLEDB) - obsolète.


le EwsEditor a déménagé sur github: github.com/dseph/EwsEditor
Opmet le

10

Voici un vieux code que j'avais pour faire WebDAV. Je pense qu'il a été écrit contre Exchange 2003, mais je ne m'en souviens plus. N'hésitez pas à l'emprunter si c'est utile ...

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/me@domain.com/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/me@domain.com/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/me@domain.com/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;
    }
}

Et modèle.

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

1
REMARQUE: la prise en charge WebDAV est supprimée d'Exchange Server 2010, utilisez plutôt EWS.
Our Man in Bananas


0

Si votre serveur Exchange est configuré pour prendre en charge POP ou IMAP, c'est une solution simple.

Une autre option est l'accès WebDAV. il y a une bibliothèque disponible pour cela. Cela pourrait être votre meilleure option.

Je pense qu'il existe des options utilisant des objets COM pour accéder à Exchange, mais je ne sais pas à quel point c'est facile.

Tout dépend de ce à quoi votre administrateur est prêt à vous donner accès, je suppose.


0

Vous devriez pouvoir utiliser MAPI pour accéder à la boîte aux lettres et obtenir les informations dont vous avez besoin. Malheureusement, la seule bibliothèque .NET MAPI (MAPI33) que je connaisse ne semble pas être maintenue. C'était un excellent moyen d'accéder à MAPI via .NET, mais je ne peux pas parler de son efficacité maintenant. Il y a plus d'informations sur l'endroit où vous pouvez l'obtenir ici: Emplacement de téléchargement pour MAPI33.dll?



0

Une option consiste à utiliser Outlook. Nous avons une application de gestion de courrier qui accède à un serveur d'échange et utilise Outlook comme interface. C'est sale mais ça marche.

Exemple de 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);
        }

1
Si je veux utiliser le service Windows dans Win2003 pour accéder à Exchange 2003 ?? J'ai besoin d'installer Outlook 2003 ou 2007 dans le serveur win2003?
Kiquenet
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.