Czytaj e-maile z MS Exchange w C #

91

Potrzebuję możliwości monitorowania i odczytywania wiadomości e-mail z określonej skrzynki pocztowej na serwerze MS Exchange (wewnętrznym w mojej firmie). Muszę również mieć możliwość odczytania adresu e-mail nadawcy, tematu, treści wiadomości i pobrania załącznika, jeśli istnieje.

Jaki jest najlepszy sposób na zrobienie tego przy użyciu języka C # (lub VB.NET)?

vajarov
źródło
4
Od tego czasu Microsoft wydał Exchange Web Services Managed API dla Exchange 2007 SP1 i v2010, który pozwala programowo dostać się do Twojej skrzynki pocztowej bez potrzeby Outlooka. Mam dwa artykuły na swoim blogu, w których omawiam to podejście: - C #: Pobieranie wszystkich wiadomości e-mail z serwera Exchange przy użyciu usług internetowych Exchange
ΩmegaMan
Pakiet Exchange Web Services Managed API 1.0 SDK to zalecana przez firmę Microsoft metoda programowej aktualizacji Exchange dla Exchange Server 2007 SP1 i nowszych. msdn.microsoft.com/en-us/library/dd633710(EXCHG.80).aspx
jlo

Odpowiedzi:

90

To bałagan. Interfejs MAPI lub CDO za pośrednictwem biblioteki DLL międzyoperacyjnej .NET jest oficjalnie nieobsługiwany przez firmę Microsoft - wydaje się, że działa dobrze, ale występują problemy z wyciekami pamięci z powodu różnych modeli pamięci. Możesz użyć CDOEX, ale to działa tylko na samym serwerze Exchange, a nie zdalnie; nieprzydatny. Możesz współdziałać z Outlookiem, ale teraz właśnie uzależniłeś się od Outlooka; przesada. Wreszcie, możesz skorzystać z obsługi WebDAV w Exchange 2003 , ale WebDAV jest skomplikowany, .NET ma słabe wbudowane wsparcie dla niego i (aby dodać obrażenia do obrażeń) Exchange 2007 prawie całkowicie rezygnuje z obsługi WebDAV.

Co ma zrobić facet? Skończyło się na tym, że użyłem komponentu IMAP AfterLogic do komunikacji z moim serwerem Exchange 2003 za pośrednictwem protokołu IMAP i okazało się, że działa to bardzo dobrze. (Zwykle szukam darmowych lub otwartych bibliotek, ale znalazłem wszystkie potrzebne .NET - szczególnie jeśli chodzi o niektóre dziwactwa implementacji IMAP z 2003 roku - a ta była wystarczająco tania i działała na pierwszej spróbuj. Wiem, że są inni).

Jeśli jednak Twoja organizacja korzysta z programu Exchange 2007, masz szczęście. Exchange 2007 jest wyposażony w interfejs usługi WWW oparty na SOAP, który ostatecznie zapewnia ujednolicony, niezależny od języka sposób interakcji z serwerem Exchange. Jeśli możesz uczynić 2007+ wymaganiem, to zdecydowanie jest droga do zrobienia. (Niestety, moja firma stosuje zasadę „ale rok 2003 nie jest zepsuty”).

Jeśli potrzebujesz pomostu zarówno Exchange 2003, jak i 2007, IMAP lub POP3 jest zdecydowanie najlepszym rozwiązaniem.

Mikołaja Piaseckiego
źródło
21
Usługa internetowa oparta na SOAP została zapakowana przez firmę Microsoft w celu uproszczenia dostępu - obecnie zaleca się używanie zestawu
jlo,
4
To prawie tak, jakby Microsoft zaprojektował go tak, aby nie działał z niczym innym niż Outlook
Chris S
67

Um,

Może się tu trochę za późno, ale czy to nie jest punkt dla EWS?

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

Potrzeba około 6 linii kodu, aby pobrać pocztę ze skrzynki pocztowej:

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 );
}
Wojna
źródło
5
„Zarządzany interfejs API EWS upraszcza wdrażanie aplikacji, które komunikują się z Microsoft Exchange Server 2007 z dodatkiem Service Pack 1 (SP1) i nowszymi wersjami Microsoft Exchange”
Chris S,
2
Zdaj sobie sprawę, że jest to nekropolia dla wiadomości sprzed lat, ale ten kod sprawił, że uruchomiłem podobny projekt w około pięć minut. Działało idealnie za pierwszym razem. Naprawdę bardziej współczesne / kompleksowe rozwiązanie niż wybrana odpowiedź IMO ... zwracając uwagę na odniesienie do kogokolwiek innego.
David W
2
Uwaga dotycząca uruchomienia tego. Musisz zainstalować pakiet NuGet „Microsoft Exchange WebServices”
John M
4
To zadziałało za pierwszym razem. To powinna być nowa zaakceptowana odpowiedź.
kroe761
Czy mogę wiedzieć, że gdybym miał używać adresu e-mail poza własną skrzynką pocztową w service.autodiscoverurl, będę musiał wpisać service.credentials, czy mam rację?
gymcode
19
  1. Obecnie preferowanym (Exchange 2013 i 2016) API jest EWS . Jest oparty wyłącznie na protokole HTTP i można uzyskać do niego dostęp z dowolnego języka, ale istnieją biblioteki specyficzne dla .Net i Java .

    Możesz użyć EWSEditor do zabawy z API.

  2. Rozszerzony MAPI . To jest natywny interfejs API używany przez Outlooka. Kończy się przy użyciu MSEMSdostawcy Exchange MAPI, który może komunikować się z Exchange za pomocą RPC (Exchange 2013 już go nie obsługuje) lub RPC-over-HTTP (Exchange 2007 lub nowszy) lub MAPI-over-HTTP (Exchange 2013 i nowsze).

    Samo API jest dostępne tylko z niezarządzanego C ++ lub Delphi . Możesz także użyć Redemption (dowolny język) - jego rodzina obiektów RDO jest opakowaniem Extended MAPI. Aby korzystać z rozszerzonego interfejsu MAPI, należy zainstalować program Outlook lub samodzielną (Exchange) wersję interfejsu MAPI (przy rozszerzonej obsłudze, która nie obsługuje plików Unicode PST i MSG oraz nie ma dostępu do Exchange 2016). Rozszerzony interfejs MAPI może być używany w usłudze.

    Możesz grać z API za pomocą OutlookSpy lub MFCMAPI .

  3. Model obiektów programu Outlook - nie dotyczy Exchange, ale umożliwia dostęp do wszystkich danych dostępnych w programie Outlook na komputerze, na którym działa kod. Nie można używać w usłudze.

  4. Exchange Active Sync . Firma Microsoft nie inwestuje już żadnych znaczących zasobów w ten protokół.

  5. Outlook był używany do instalowania biblioteki CDO 1.21 (opakowuje rozszerzone MAPI), ale został wycofany przez firmę Microsoft i nie otrzymuje już żadnych aktualizacji.

  6. Kiedyś istniało opakowanie .Net MAPI innej firmy o nazwie MAPI33, ale nie jest już rozwijane ani obsługiwane.

  7. WebDAV - przestarzałe.

  8. Collaborative Data Objects for Exchange (CDOEX) - przestarzałe.

  9. Exchange OLE DB Provider (EXOLEDB) - przestarzałe.

Dmitrij Streblechenko
źródło
EwsEditor przeniósł się na github: github.com/dseph/EwsEditor
Opmet
10

Oto stary kod, który miałem do zrobienia w WebDAV. Myślę, że zostało napisane przeciwko Exchange 2003, ale już nie pamiętam. Możesz go pożyczyć, jeśli jest pomocny ...

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

I model. Poczta:

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
źródło
1
UWAGA: Obsługa WebDAV została usunięta z Exchange Server 2010, zamiast tego użyj EWS.
Nasz człowiek w bananach
0

Jeśli serwer Exchange jest skonfigurowany do obsługi protokołu POP lub IMAP, jest to łatwe wyjście.

Inną opcją jest dostęp przez WebDAV. jest do tego dostępna biblioteka . To może być najlepsza opcja.

Myślę, że istnieją opcje wykorzystujące obiekty COM do uzyskiwania dostępu do Exchange, ale nie jestem pewien, jakie to łatwe.

Myślę, że wszystko zależy od tego, co dokładnie administrator zechce dać Ci dostęp.

Denis Troller
źródło
0

Powinieneś być w stanie użyć MAPI, aby uzyskać dostęp do skrzynki pocztowej i uzyskać potrzebne informacje. Niestety, jedyna znana mi biblioteka .NET MAPI (MAPI33) wydaje się nie być konserwowana. Kiedyś był to świetny sposób na dostęp do MAPI przez .NET, ale nie mogę teraz mówić o jego skuteczności. Więcej informacji na temat tego, gdzie można ją pobrać, można znaleźć tutaj: Lokalizacja pobierania pliku MAPI33.dll?

Chris Hynes
źródło
0

Jedną z opcji jest użycie programu Outlook. Mamy aplikację do zarządzania pocztą, która uzyskuje dostęp do serwera wymiany i używa programu Outlook jako interfejsu. Jest brudny, ale działa.

Przykładowy kod:

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
źródło
1
Jeśli chcę używać usługi Windows w Win2003 w celu uzyskania dostępu do programu Exchange 2003? Muszę zainstalować program Outlook 2003 lub 2007 na serwerze win2003?
Kiquenet,