Leggi le email di MS Exchange in C #


91

Ho bisogno della capacità di monitorare e leggere la posta elettronica da una particolare casella di posta su un server MS Exchange (interno alla mia azienda). Devo anche essere in grado di leggere l'indirizzo e-mail, l'oggetto, il corpo del messaggio del mittente e scaricare un allegato, se presente.

Qual è il modo migliore per farlo utilizzando C # (o VB.NET)?


4
Da allora Microsoft ha rilasciato l'API gestita dei servizi Web di Exchange per Exchange 2007 SP1 e v2010 che consente di accedere in modo programmatico alla cassetta postale senza la necessità di Outlook. Ho due articoli sul mio blog che discutono di questo approccio: - C #: ottenere tutte le email da Exchange utilizzando i servizi Web di Exchange
ΩmegaMan

L'SDK di Exchange Web Services Managed API 1.0 è il metodo consigliato da Microsoft per l'aggiornamento programmatico di Exchange per Exchange Server 2007 SP1 e versioni successive. msdn.microsoft.com/en-us/library/dd633710(EXCHG.80).aspx
jlo

Risposte:


90

È un disastro. MAPI o CDO tramite una DLL di interoperabilità .NET non è ufficialmente supportato da Microsoft: sembrerà funzionare correttamente, ma ci sono problemi con perdite di memoria a causa dei diversi modelli di memoria. È possibile utilizzare CDOEX, ma funziona solo sul server Exchange stesso, non in remoto; inutili. Potresti interagire con Outlook, ma ora hai appena creato una dipendenza da Outlook; eccessivo. Infine, è possibile utilizzare il supporto WebDAV di Exchange 2003 , ma WebDAV è complicato, .NET ha uno scarso supporto integrato e (per aggiungere la beffa al danno) Exchange 2007 quasi completamente elimina il supporto WebDAV.

Cosa deve fare un ragazzo? Ho finito per utilizzare il componente IMAP di AfterLogic per comunicare con il mio server Exchange 2003 tramite IMAP, e questo ha funzionato molto bene. (Di solito cerco librerie libere o open source, ma ho trovato tutte quelle .NET che volevano, specialmente quando si tratta di alcune delle stranezze dell'implementazione IMAP del 2003, e questa era abbastanza economica e ha funzionato sul primo prova. So che ce ne sono altri là fuori.)

Se la tua organizzazione utilizza Exchange 2007, tuttavia, sei fortunato. Exchange 2007 viene fornito con un'interfaccia del servizio Web basata su SOAP che fornisce finalmente un modo unificato e indipendente dalla lingua di interagire con il server Exchange. Se puoi rendere 2007+ un requisito, questa è sicuramente la strada da percorrere. (Purtroppo per me, la mia azienda ha una politica "ma il 2003 non è rotto".)

Se è necessario collegare sia Exchange 2003 che 2007, IMAP o POP3 è sicuramente la strada da percorrere.


21
Il servizio Web basato su SOAP è stato integrato da Microsoft per semplificare l'accesso: ora è consigliabile utilizzare l'SDK di Exchange Web Services Managed API 1.0: msdn.microsoft.com/en-us/library/dd633710(EXCHG.80).aspx
jlo

4
È quasi come se Microsoft lo progettasse per essere inutilizzabile con qualsiasi cosa tranne Outlook
Chris S

67

Um,

Potrei essere un po 'in ritardo qui, ma non è questo il punto di EWS?

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

Occorrono circa 6 righe di codice per ricevere la posta da una casella di posta:

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 gestita di EWS semplifica l'implementazione delle applicazioni che comunicano con Microsoft Exchange Server 2007 Service Pack 1 (SP1) e versioni successive di Microsoft Exchange"
Chris S

2
Renditi conto che questo è essenzialmente un necrobump per un messaggio vecchio di anni, ma questo codice mi ha fatto funzionare per un progetto simile in circa cinque minuti. Ha funzionato perfettamente la prima volta. Davvero una soluzione più contemporanea / completa rispetto alla risposta selezionata IMO ... notando per riferimento di chiunque altro.
David W

2
Nota su come farlo funzionare. È necessario installare il pacchetto NuGet "Microsoft Exchange WebServices"
John M

4
Questo ha funzionato per me al primo tentativo. Questa dovrebbe essere la nuova risposta accettata.
kroe761

Posso sapere se dovessi utilizzare un indirizzo e-mail diverso dalla mia casella di posta in service.autodiscoverurl, service.credentialsdovrò inserire il , ho ragione?
gymcode

19
  1. L'API attualmente preferita (Exchange 2013 e 2016) è EWS . È puramente basato su HTTP ed è accessibile da qualsiasi linguaggio, ma ci sono librerie specifiche .Net e Java .

    Puoi utilizzare EWSEditor per giocare con l'API.

  2. MAPI estesa . Questa è l'API nativa utilizzata da Outlook. Finisce per utilizzare il MSEMSprovider MAPI di Exchange, che può comunicare con Exchange utilizzando RPC (Exchange 2013 non lo supporta più) o RPC-over-HTTP (Exchange 2007 o più recente) o MAPI-over-HTTP (Exchange 2013 e più recente).

    È possibile accedere all'API stessa solo da C ++ o Delphi non gestiti . È inoltre possibile utilizzare Redemption (qualsiasi lingua): la sua famiglia di oggetti RDO è un wrapper MAPI esteso. Per utilizzare MAPI estesa, è necessario installare Outlook o la versione autonoma (Exchange) di MAPI (con supporto esteso e non supporta i file Unicode PST e MSG e non può accedere a Exchange 2016). MAPI estesa può essere utilizzata in un servizio.

    Puoi giocare con l'API utilizzando OutlookSpy o MFCMAPI .

  3. Modello a oggetti di Outlook : non specifico di Exchange, ma consente l'accesso a tutti i dati disponibili in Outlook sulla macchina in cui viene eseguito il codice. Non può essere utilizzato in un servizio.

  4. Exchange Active Sync . Microsoft non investe più risorse significative in questo protocollo.

  5. Outlook installava la libreria CDO 1.21 (include MAPI estesa), ma era stata deprecata da Microsoft e non riceve più alcun aggiornamento.

  6. C'era un wrapper .Net MAPI di terze parti chiamato MAPI33, ma non viene più sviluppato o supportato.

  7. WebDAV - deprecato.

  8. Collaborative Data Objects for Exchange (CDOEX) - deprecato.

  9. Provider OLE DB di Exchange (EXOLEDB) - deprecato.


l'EwsEditor è stato spostato su github: github.com/dseph/EwsEditor
Opmet

10

Ecco un vecchio codice che avevo in giro per fare WebDAV. Penso che sia stato scritto contro Exchange 2003, ma non ricordo più. Sentiti libero di prenderlo in prestito se è 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;
    }
}

E modello.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; }
    }
}

1
NOTA: il supporto WebDAV è stato eliminato da Exchange Server 2010, utilizzare invece EWS.
Our Man in Bananas


0

Se il tuo server Exchange è configurato per supportare POP o IMAP, questa è una facile soluzione.

Un'altra opzione è l'accesso WebDAV. c'è una libreria disponibile per questo. Questa potrebbe essere la tua migliore opzione.

Penso che ci siano opzioni che utilizzano oggetti COM per accedere a Exchange, ma non sono sicuro di quanto sia facile.

Tutto dipende da cosa esattamente il tuo amministratore è disposto a darti l'accesso immagino.


0

Dovresti essere in grado di utilizzare MAPI per accedere alla casella di posta e ottenere le informazioni necessarie. Sfortunatamente l'unica libreria .NET MAPI (MAPI33) che conosco sembra non essere più mantenuta. Questo era un ottimo modo per accedere a MAPI tramite .NET, ma ora non posso parlare della sua efficacia. Sono disponibili ulteriori informazioni su dove è possibile ottenerlo qui: Percorso di download per MAPI33.dll?



0

Un'opzione è utilizzare Outlook. Abbiamo un'applicazione di gestione della posta che accede a un server di scambio e utilizza Outlook come interfaccia. È sporco ma funziona.

Codice di esempio:

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
Se voglio utilizzare il servizio Windows in Win2003 per l'accesso a Exchange 2003 ?? Devo installare Outlook 2003 o 2007 in Server win2003?
Kiquenet
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.