Читать электронную почту MS Exchange на C #

91

Мне нужна возможность отслеживать и читать электронную почту из определенного почтового ящика на сервере MS Exchange (внутреннем для моей компании). Мне также необходимо иметь возможность читать адрес электронной почты отправителя, тему, текст сообщения и загружать вложения, если они есть.

Как лучше всего это сделать с помощью C # (или VB.NET)?

Ваджаров
источник
4
С тех пор Microsoft выпустила управляемый API-интерфейс веб-служб Exchange для Exchange 2007 с пакетом обновления 1 (SP1) и v2010, который позволяет программным способом попасть в ваш почтовый ящик без необходимости использования Outlook. В моем блоге есть две статьи, в которых обсуждается этот подход: - C #: получение всех писем из Exchange с помощью веб-служб Exchange
ΩmegaMan
Пакет SDK Managed API 1.0 веб-служб Exchange - это рекомендованный Microsoft метод программного обновления Exchange для Exchange Server 2007 SP1 и выше. msdn.microsoft.com/en-us/library/dd633710(EXCHG.80).aspx
jlo

Ответы:

90

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

Что делать парню? В итоге я использовал компонент IMAP AfterLogic для связи с моим сервером Exchange 2003 через IMAP, и это в итоге работало очень хорошо. (Обычно я ищу бесплатные библиотеки или библиотеки с открытым исходным кодом, но я обнаружил, что все .NET-библиотеки нужны - особенно когда дело доходит до некоторых причуд реализации IMAP 2003 года - и эта была достаточно дешевой и работала над первым попробуй. Я знаю, что есть и другие.)

Однако если ваша организация использует Exchange 2007, вам повезло. Exchange 2007 поставляется с интерфейсом веб-службы на основе SOAP, который наконец обеспечивает унифицированный, независимый от языка способ взаимодействия с сервером Exchange. Если вы можете сделать 2007+ обязательным, это определенно правильный путь. (К сожалению для меня, моя компания придерживается политики «но 2003 год не нарушен».)

Если вам нужно соединить как Exchange 2003, так и 2007, IMAP или POP3 определенно лучший вариант.

Николай Пясецкий
источник
21
Веб-служба на основе SOAP была упакована Microsoft для упрощения доступа - теперь рекомендуется использовать пакет SDK для Exchange Web Services Managed API 1.0: msdn.microsoft.com/en-us/library/dd633710(EXCHG.80).aspx
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 ... отмечая для кого-либо еще.
Дэвид У
2
Обратите внимание на то, как это запустить. Вам необходимо установить пакет NuGet «Microsoft Exchange WebServices»
Джон М.
4
У меня это сработало с первой попытки. Это должен быть новый принятый ответ.
kroe761
Могу ли я узнать, что если бы я использовал адрес электронной почты отдельно от своего почтового ящика service.autodiscoverurl, мне нужно было бы ввести service.credentials, правильно?
gymcode
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 . Вы также можете использовать Redemption (любой язык) - его семейство объектов RDO является расширенной оболочкой MAPI. Чтобы использовать расширенный MAPI, вам необходимо установить Outlook или автономную (Exchange) версию MAPI (с расширенной поддержкой, она не поддерживает файлы Unicode PST и MSG и не может получить доступ к 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; }
    }
}
CodingWithSpike
источник
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