Читання електронної пошти MS Exchange на C #


91

Мені потрібна можливість стежити за електронною поштою та читати її з певної поштової скриньки на сервері MS Exchange (внутрішній для моєї компанії). Мені також потрібно мати можливість прочитати електронну адресу відправника, тему, тіло повідомлення та завантажити вкладення, якщо таке є.

Який найкращий спосіб зробити це за допомогою C # (або VB.NET)?


4
З тих пір корпорація Майкрософт випустила API для керування веб-службами Exchange для Exchange 2007 з пакетом оновлень 1 і v2010, що дозволяє систематично потрапляти у вашу поштову скриньку без потреби в Outlook. У моєму блозі є дві статті, які обговорюють цей підхід: - C #: Отримання всіх електронних листів із Exchange за допомогою веб-служб Exchange
ΩmegaMan

SDK, керований API веб-служб Exchange, - це рекомендований Microsoft спосіб програмного оновлення Exchange для Exchange Server 2007 SP1 і вище. msdn.microsoft.com/en-us/library/dd633710(EXCHG.80).aspx
JLo

Відповіді:


90

Це безлад. MAPI або CDO через .NET interop DLL офіційно не підтримується корпорацією Майкрософт - це, здається, справно працює, але є проблеми з витоками пам'яті через різні моделі пам'яті. Ви можете використовувати CDOEX, але це працює лише на самому сервері Exchange, а не віддалено; марно. Ви можете взаємодіяти з Outlook, але зараз ви щойно зробили залежність від Outlook; надмірний рівень. Нарешті, ви можете скористатись підтримкою WebDAV Exchange 2003 , але WebDAV складний, .NET має погану вбудовану підтримку, і (щоб додати образу до травми) Exchange 2007 майже повністю відмовляється від підтримки WebDAV.

Що робити хлопцеві? У підсумку я використав компонент IMAP AfterLogic для зв’язку з моїм сервером Exchange 2003 через IMAP, і це в кінцевому підсумку працювало дуже добре. (Зазвичай я шукаю безкоштовні бібліотеки або бібліотеки з відкритим кодом, але я виявив, що всі, хто бажає. спробуйте. Я знаю, що там є й інші.)

Однак якщо ваша організація працює на Exchange 2007, вам пощастило. Exchange 2007 постачається з інтерфейсом веб-служби на основі SOAP, який, нарешті, забезпечує уніфікований, незалежний від мови спосіб взаємодії з сервером Exchange. Якщо ви можете встановити вимогу до 2007+, це, безумовно, шлях. (На жаль, моя компанія має політику "але 2003 рік не порушений").

Якщо вам потрібно поєднати Exchange 2003 та 2007, IMAP або POP3 - це безперечно шлях.


21
Веб-служба на базі SOAP була укладена корпорацією Майкрософт для спрощення доступу - зараз рекомендується застосовувати пакет
jlo

4
Це майже так, ніби Microsoft розробила його для того, щоб не працювати з будь-чим, окрім Outlook
Кріс С

67

Гм,

Я, можливо, трохи запізнився тут, але хіба це не сенс у EWS?

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

Для отримання пошти з поштової скриньки потрібно близько 6 рядків коду:

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
"Керований API EWS спрощує впровадження програм, які взаємодіють із Microsoft Exchange Server 2007 з пакетом оновлень 1 (SP1) та пізнішими версіями Microsoft Exchange"
Кріс С,

2
Зрозумійте, що це, по суті, некробум для багаторічного повідомлення, але цей код змусив мене запустити подібний проект приблизно за п’ять хвилин. Працював ідеально з першого разу. Дійсно, більш сучасне / вичерпне рішення, ніж обрана відповідь IMO ... зазначаючи для посилання будь-кого іншого.
David W

2
Примітка щодо запуску цього. Вам потрібно встановити пакет NuGet "Microsoft Exchange WebServices"
Джон М

4
Це спрацювало для мене з першої спроби. Це має бути новою прийнятою відповіддю.
kroe761

Чи можу я знати, якщо мені слід використовувати адресу електронної пошти крім власної поштової скриньки service.autodiscoverurl, мені потрібно буде ввести service.credentials, чи не так?
гімкод

19
  1. На даний момент кращим (Exchange 2013 та 2016) API є EWS . Він повністю заснований на HTTP і може бути доступний з будь-якої мови, але є бібліотеки .Net та Java .

    Ви можете використовувати EWSEditor, щоб грати з API.

  2. Розширений MAPI . Це власний API, який використовується Outlook. В кінцевому підсумку використовується MSEMSпровайдер Exchange MAPI, який може спілкуватися з Exchange, використовуючи RPC (Exchange 2013 більше не підтримує його) або RPC-over-HTTP (Exchange 2007 або новіша версія) або MAPI-over-HTTP (Exchange 2013 та новіша версія).

    До самого API можна отримати доступ лише з некерованих C ++ або Delphi . Ви також можете використовувати викуп (будь-яка мова) - його сімейство об'єктів RDO є розширеною обгорткою MAPI. Щоб використовувати розширений MAPI, вам потрібно встановити Outlook або автономну (Exchange) версію MAPI (на розширеній підтримці, і він не підтримує файли PST та MSG Unicode і не може отримати доступ до Exchange 2016). Розширений MAPI можна використовувати в службі.

    Ви можете грати з API за допомогою OutlookSpy або MFCMAPI .

  3. Об'єктна модель Outlook - не специфічна для Exchange, але вона забезпечує доступ до всіх даних, доступних у програмі Outlook на машині, де працює код. Не можна використовувати в службі.

  4. Exchange Active Sync . Microsoft більше не вкладає в цей протокол значних ресурсів.

  5. Outlook використовувався для встановлення бібліотеки CDO 1.21 (вона обгортає розширений MAPI), але вона була застаріла від Microsoft і більше не отримує жодних оновлень.

  6. Раніше існувала стороння обгортка .Net MAPI з назвою MAPI33, але вона більше не розробляється і не підтримується.

  7. WebDAV - застарілий.

  8. Об'єкти спільних даних для обміну (CDOEX) - застарілі.

  9. Exchange OLE DB Provider (EXOLEDB) - застарілий.


EwsEditor переїхав до github: github.com/dseph/EwsEditor
Opmet

10

Ось старий код, який я мав навколо, щоб зробити WebDAV. Я думаю, що це було написано проти Exchange 2003, але я більше не пам’ятаю. Не соромтеся позичати його, якщо це корисно ...

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

І модель.

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
ПРИМІТКА. Підтримка WebDAV припинена з Exchange Server 2010, замість цього використовуйте EWS.
Наш чоловік у бананах


0

Якщо ваш сервер Exchange налаштований на підтримку POP або IMAP, це простий вихід.

Інший варіант - доступ до WebDAV. для цього існує бібліотека . Це може бути ваш найкращий варіант.

Я думаю, що є варіанти використання об’єктів COM для доступу до Exchange, але я не впевнений, наскільки це просто.

Все залежить від того, що саме ваш адміністратор готовий надати вам доступ, я думаю.


0

Ви повинні мати можливість використовувати MAPI для доступу до поштової скриньки та отримання необхідної інформації. На жаль, єдина бібліотека .NET MAPI (MAPI33), яку я знаю, здається, не підтримується. Раніше це був чудовий спосіб отримати доступ до MAPI через .NET, але я не можу зараз говорити про його ефективність. Тут є додаткова інформація про те, де ви можете її отримати тут: Місце завантаження для MAPI33.dll?



0

Одним із варіантів є використання Outlook. У нас є програма управління поштою, яка отримує доступ до сервера обміну та використовує Outlook як інтерфейс. Це брудно, але це працює.

Приклад коду:

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
Якщо я хочу використовувати службу Windows у Win2003 для доступу до Exchange 2003 ?? Мені потрібно встановити Outlook 2003 або 2007 на сервері win2003?
Kiquenet
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.