Lesen Sie die MS Exchange-E-Mail in C #

90

Ich muss in der Lage sein, E-Mails von einem bestimmten Postfach auf einem MS Exchange Server (unternehmensintern) zu überwachen und zu lesen. Ich muss auch in der Lage sein, die E-Mail-Adresse, den Betreff und den Nachrichtentext des Absenders zu lesen und gegebenenfalls einen Anhang herunterzuladen.

Was ist der beste Weg, dies mit C # (oder VB.NET) zu tun?

Vajarov
quelle
4
Microsoft hat seitdem die Exchange Web Services Managed API für Exchange 2007 SP1 und v2010 veröffentlicht, mit der Sie programmgesteuert in Ihr Postfach gelangen können, ohne Outlook zu benötigen. Ich habe zwei Artikel in meinem Blog, die diesen Ansatz diskutieren: - C #: Abrufen aller E-Mails von Exchange mithilfe von Exchange-Webdiensten
ΩmegaMan
Das von Exchange Web Services verwaltete API 1.0 SDK ist die von Microsoft empfohlene Methode zum programmgesteuerten Aktualisieren von Exchange für Exchange Server 2007 SP1 und höher. msdn.microsoft.com/en-us/library/dd633710(EXCHG.80).aspx
jlo

Antworten:

90

Es ist ein Chaos. MAPI oder CDO über eine .NET-Interop-DLL wird von Microsoft offiziell nicht unterstützt - es scheint gut zu funktionieren, aber es gibt Probleme mit Speicherlecks aufgrund ihrer unterschiedlichen Speichermodelle. Sie könnten CDOEX verwenden, dies funktioniert jedoch nur auf dem Exchange-Server selbst, nicht remote. nutzlos. Sie könnten mit Outlook zusammenarbeiten, aber jetzt haben Sie gerade eine Abhängigkeit von Outlook hergestellt. Overkill. Schließlich könnten Sie die WebDAV-Unterstützung von Exchange 2003 verwenden , aber WebDAV ist kompliziert, .NET verfügt nur über eine unzureichende integrierte Unterstützung, und Exchange 2007 stellt die WebDAV-Unterstützung fast vollständig ein .

Was kann ein Mann tun? Am Ende habe ich die IMAP-Komponente von AfterLogic verwendet, um über IMAP mit meinem Exchange 2003-Server zu kommunizieren, und dies hat sehr gut funktioniert. (Normalerweise suche ich nach kostenlosen oder Open-Source-Bibliotheken, aber ich fand, dass alle .NET-Bibliotheken fehlen - insbesondere, wenn es um einige der Macken der IMAP-Implementierung von 2003 geht - und diese war billig genug und arbeitete an der ersten versuche es. Ich weiß, dass es da draußen noch andere gibt.)

Wenn sich Ihre Organisation jedoch in Exchange 2007 befindet, haben Sie Glück. Exchange 2007 wird mit einer SOAP-basierten Webdienstschnittstelle geliefert , die endlich eine einheitliche, sprachunabhängige Art der Interaktion mit dem Exchange-Server bietet. Wenn Sie 2007+ zu einer Anforderung machen können, ist dies definitiv der richtige Weg. (Leider hat mein Unternehmen die Richtlinie "Aber 2003 ist nicht gebrochen".)

Wenn Sie Exchange 2003 und 2007 überbrücken müssen, ist IMAP oder POP3 definitiv der richtige Weg.

Nicholas Piasecki
quelle
21
Der SOAP-basierte Webdienst wurde von Microsoft verpackt, um den Zugriff zu vereinfachen. Es wird jetzt empfohlen, das verwaltete API 1.0-SDK von Exchange Web Services zu verwenden: msdn.microsoft.com/en-us/library/dd633710(EXCHG.80).aspx
Jlo
4
Es ist fast so, als hätte Microsoft es so konzipiert, dass es mit nichts anderem als Outlook nicht funktionsfähig ist
Chris S
67

Äh,

Ich bin hier vielleicht etwas zu spät, aber ist das nicht der Punkt für EWS?

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

Benötigt ungefähr 6 Codezeilen, um die Mail aus einer Mailbox zu erhalten:

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 );
}
Krieg
quelle
5
"Die EWS Managed API vereinfacht die Implementierung von Anwendungen, die mit Microsoft Exchange Server 2007 Service Pack 1 (SP1) und späteren Versionen von Microsoft Exchange kommunizieren"
Chris S
2
Erkenne, dass dies im Wesentlichen ein Nekrobump für eine jahrelange Nachricht ist, aber dieser Code hat mich in etwa fünf Minuten für ein ähnliches Projekt zum Laufen gebracht. Hat beim ersten Mal perfekt funktioniert. Wirklich eine zeitgemäßere / umfassendere Lösung als die ausgewählte Antwort IMO ... als Referenz für andere.
David W
2
Hinweis zum Laufen bringen. Sie müssen das NuGet-Paket "Microsoft Exchange WebServices"
John M
4
Dies funktionierte bei mir beim ersten Versuch. Dies sollte die neu akzeptierte Antwort sein.
kroe761
Darf ich wissen, ob ich eine E-Mail-Adresse außer meiner eigenen Mailbox verwenden soll ? Ich service.autodiscoverurlmuss die eingeben service.credentials, habe ich Recht?
Gymcode
19
  1. Die derzeit bevorzugte API (Exchange 2013 und 2016) ist EWS . Es ist rein HTTP-basiert und kann von jeder Sprache aus aufgerufen werden, es gibt jedoch .NET- und Java- spezifische Bibliotheken.

    Sie können EWSEditor verwenden , um mit der API zu spielen.

  2. Erweiterter MAPI . Dies ist die native API, die von Outlook verwendet wird. Am Ende wird der MSEMSExchange-MAPI-Anbieter verwendet, der über RPC (Exchange 2013 unterstützt dies nicht mehr) oder RPC-over-HTTP (Exchange 2007 oder neuer) oder MAPI-over-HTTP (Exchange 2013 und neuer) mit Exchange kommunizieren kann.

    Auf die API selbst kann nur über nicht verwaltetes C ++ oder Delphi zugegriffen werden . Sie können auch Redemption (jede Sprache) verwenden RDO-Objektfamilie ist ein erweiterter MAPI-Wrapper. Um Extended MAPI verwenden zu können, müssen Sie entweder Outlook oder die Standalone-Version (Exchange) von MAPI installieren (bei erweiterter Unterstützung werden Unicode PST- und MSG-Dateien nicht unterstützt und es kann nicht auf Exchange 2016 zugegriffen werden). Extended MAPI kann in einem Dienst verwendet werden.

    Sie können mit der API über OutlookSpy oder MFCMAPI spielen .

  3. Outlook-Objektmodell - nicht Exchange-spezifisch, ermöglicht jedoch den Zugriff auf alle in Outlook verfügbaren Daten auf dem Computer, auf dem der Code ausgeführt wird. Kann nicht in einem Dienst verwendet werden.

  4. Exchange ActiveSync . Microsoft investiert keine wesentlichen Ressourcen mehr in dieses Protokoll.

  5. Outlook wurde zum Installieren der CDO 1.21-Bibliothek verwendet (es schließt Extended MAPI ein), wurde jedoch von Microsoft nicht mehr unterstützt und erhält keine Updates mehr.

  6. Früher gab es einen .NET MAPI-Wrapper von Drittanbietern namens MAPI33, der jedoch nicht mehr entwickelt oder unterstützt wird.

  7. WebDAV - veraltet.

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

  9. Exchange OLE DB Provider (EXOLEDB) - veraltet.

Dmitry Streblechenko
quelle
Der EwsEditor ist zu github gewechselt: github.com/dseph/EwsEditor
Opmet
10

Hier ist ein alter Code, den ich für WebDAV herumliegen hatte. Ich denke, es wurde gegen Exchange 2003 geschrieben, aber ich erinnere mich nicht mehr. Fühlen Sie sich frei, es auszuleihen, wenn es hilfreich ist ...

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

Und 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; }
    }
}
CodingWithSpike
quelle
1
ANMERKUNG: Die WebDAV-Unterstützung wird von Exchange Server 2010 entfernt. Verwenden Sie stattdessen EWS.
Unser Mann in Bananen
0

Wenn Ihr Exchange-Server für die Unterstützung von POP oder IMAP konfiguriert ist, ist dies ein einfacher Ausweg.

Eine weitere Option ist der WebDAV-Zugriff. Es gibt eine Bibliothek Verfügung. Dies könnte Ihre beste Option sein.

Ich denke, es gibt Optionen, die COM-Objekte verwenden, um auf Exchange zuzugreifen, aber ich bin mir nicht sicher, wie einfach es ist.

Es hängt alles davon ab, was genau Ihr Administrator bereit ist, Ihnen Zugriff zu gewähren, denke ich.

Denis Troller
quelle
0

Sie sollten in der Lage sein, mit MAPI auf das Postfach zuzugreifen und die benötigten Informationen abzurufen. Leider scheint die einzige mir bekannte .NET MAPI-Bibliothek (MAPI33) nicht gepflegt zu sein. Früher war dies eine großartige Möglichkeit, über .NET auf MAPI zuzugreifen, aber ich kann jetzt nicht über seine Wirksamkeit sprechen. Weitere Informationen dazu, wo Sie sie erhalten können, finden Sie hier: Speicherort für MAPI33.dll herunterladen?

Chris Hynes
quelle
0

Eine Möglichkeit ist die Verwendung von Outlook. Wir haben eine Mail-Manager-Anwendung, die auf einen Exchange-Server zugreift und Outlook als Schnittstelle verwendet. Es ist schmutzig, aber es funktioniert.

Beispielcode:

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
quelle
1
Wenn ich Windows Service in Win2003 für den Zugriff auf Exchange 2003 verwenden möchte? Ich muss Outlook 2003 oder 2007 in Server Win2003 installieren.
Kiquenet