在 C# 中阅读 MS Exchange 电子邮件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/652549/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 11:55:38  来源:igfitidea点击:

Read MS Exchange email in C#

c#emailexchange-servermapi

提问by vajarov

I need the ability to monitor for and read e-mail from a particular mailbox on a MS Exchange Server (internal to my company). I also need to be able to read the sender's e-mail address, subject, message body and download an attachment, if any.

我需要能够监视和读取来自 MS Exchange Server(我公司内部)上的特定邮箱的电子邮件。我还需要能够阅读发件人的电子邮件地址、主题、邮件正文并下载附件(如果有)。

What is the best way to do this using C# (or VB.NET)?

使用 C#(或 VB.NET)执行此操作的最佳方法是什么?

采纳答案by Nicholas Piasecki

It's a mess. MAPI or CDO via a .NET interop DLL is officially unsupported by Microsoft--it will appear to work fine, but there are problems with memory leaks due to their differing memory models. You could use CDOEX, but that only works on the Exchange server itself, not remotely; useless. You could interop with Outlook, but now you've just made a dependency on Outlook; overkill. Finally, you could use Exchange 2003's WebDAV support, but WebDAV is complicated, .NET has poor built-in support for it, and (to add insult to injury) Exchange 2007 nearly completely dropsWebDAV support.

一团糟。Microsoft 正式不支持通过.NET 互操作 DLL 的 MAPI 或 CDO -- 它看起来可以正常工作,但由于内存模型不同,存在内存泄漏问题。您可以使用 CDOEX,但这仅适用于 Exchange 服务器本身,不能远程使用;无用。您可以与 Outlook 互操作,但现在您只是依赖于 Outlook;矫枉过正。最后,您可以使用Exchange 2003 的 WebDAV 支持,但 WebDAV 很复杂,.NET 对它的内置支持很差,而且(雪上加霜)Exchange 2007几乎完全放弃了WebDAV 支持。

What's a guy to do? I ended up using AfterLogic's IMAP componentto communicate with my Exchange 2003 server via IMAP, and this ended up working very well. (I normally seek out free or open-source libraries, but I found all of the .NET ones wanting--especially when it comes to some of the quirks of 2003's IMAP implementation--and this one was cheap enough and worked on the first try. I know there are others out there.)

一个人要做什么?我最终使用AfterLogic 的 IMAP 组件通过 IMAP 与我的 Exchange 2003 服务器进行通信,最终效果很好。(我通常会寻找免费或开源库,但我发现所有 .NET 库都需要——尤其是在涉及 2003 年 IMAP 实现的一些怪癖时——而且这个库足够便宜并且在第一个试试。我知道还有其他人在那里。)

If your organization is on Exchange 2007, however, you're in luck. Exchange 2007 comes with a SOAP-based Web service interfacethat finally provides a unified, language-independent way of interacting with the Exchange server. If you can make 2007+ a requirement, this is definitely the way to go. (Sadly for me, my company has a "but 2003 isn't broken" policy.)

但是,如果您的组织使用的是 Exchange 2007,那么您很幸运。Exchange 2007 带有一个基于 SOAP 的 Web 服务接口,它最终提供了一种与 Exchange 服务器交互的统一的、独立于语言的方式。如果您可以要求 2007+,这绝对是要走的路。(对我来说可悲的是,我的公司有一个“但 2003 年并没有被打破”的政策。)

If you need to bridge both Exchange 2003 and 2007, IMAP or POP3 is definitely the way to go.

如果您需要桥接 Exchange 2003 和 2007,IMAP 或 POP3 绝对是最佳选择。

回答by Denis Troller

If your Exchange server is configured to support POP or IMAP, that's an easy way out.

如果您的 Exchange 服务器配置为支持 POP 或 IMAP,这是一个简单的方法。

Another option is WebDAV access. there is a libraryavailable for that. This might be your best option.

另一种选择是 WebDAV 访问。有一个可用的图书馆。这可能是您最好的选择。

I think there are options using COM objects to access Exchange, but I'm not sure how easy it is.

我认为有使用 COM 对象访问 Exchange 的选项,但我不确定它有多容易。

It all depends on what exactly your administrator is willing to give you access to I guess.

这完全取决于您的管理员到底愿意让您访问我猜的内容。

回答by Chris Hynes

You should be able to use MAPI to access the mailbox and get the information you need. Unfortunately the only .NET MAPI library (MAPI33) I know of seems to be unmaintained. This used to be a great way to access MAPI through .NET, but I can't speak to its effectiveness now. There's more information about where you can get it here: Download location for MAPI33.dll?

您应该能够使用 MAPI 访问邮箱并获取您需要的信息。不幸的是,我所知道的唯一的 .NET MAPI 库 (MAPI33) 似乎没有维护。这曾经是通过 .NET 访问 MAPI 的好方法,但我现在不能说它的有效性。此处提供了有关从何处获取它的更多信息:MAPI33.dll 的下载位置?

回答by Eldila

I used code that was published on CodeProject.com. If you want to use POP3, it is one of the better solutions that I have found.

我使用了在 CodeProject.com 上发布的代码。如果您想使用 POP3,它是我发现的更好的解决方案之一。

回答by Paul Rowland

I got a solution working in the end using Redemption, have a look at these questions...

我最终使用 Redemption 得到了一个解决方案,看看这些问题......

回答by CodingWithSpike

Here is some old code I had laying around to do WebDAV. I think it was written against Exchange 2003, but I don't remember any more. Feel free to borrow it if its helpful...

这是我用来做 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/[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;
    }
}

And model.Mail:

和模型.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; }
    }
}

回答by duncane

One option is to use Outlook. We have a mail manager application that access an exchange server and uses outlook as the interface. Its dirty but it works.

一种选择是使用 Outlook。我们有一个邮件管理器应用程序,它访问交换服务器并使用 Outlook 作为界面。它很脏,但它有效。

Example code:

示例代码:

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

回答by War

Um,

嗯,

I might be a bit too late here but isn't this kinda the point to EWS ?

我在这里可能有点太晚了,但这不是 EWS 的重点吗?

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

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

Takes about 6 lines of code to get the mail from a mailbox:

从邮箱中获取邮件大约需要 6 行代码:

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

回答by Dmitry Streblechenko

  1. The currently preferred (Exchange 2013 and 2016) API is EWS. It is purely HTTP based and can be accessed from any language, but there are .Netand Javaspecific libraries.

    You can use EWSEditorto play with the API.

  2. Extended MAPI. This is the native API used by Outlook. It ends up using the MSEMSExchange MAPI provider, which can talk to Exchange using RPC (Exchange 2013 no longer supports it) or RPC-over-HTTP (Exchange 2007 or newer) or MAPI-over-HTTP (Exchange 2013 and newer).

    The API itself can only be accessed from unmanaged C++ or Delphi. You can also use Redemption(any language) - its RDOfamily of objects is an Extended MAPI wrapper. To use Extended MAPI, you need to install either Outlook or the standalone (Exchange) version of MAPI(on extended support, and it does not support Unicode PST and MSG files and cannot access Exchange 2016). Extended MAPI can be used in a service.

    You can play with the API using OutlookSpyor MFCMAPI.

  3. Outlook Object Model- not Exchange specific, but it allows access to all data available in Outlook on the machine where the code runs. Cannot be used in a service.

  4. Exchange Active Sync. Microsoft no longer invests any significant resources into this protocol.

  5. Outlook used to install CDO 1.21 library (it wraps Extended MAPI), but it had been deprecated by Microsoft and no longer receives any updates.

  6. There used to be a third-party .Net MAPI wrapper called MAPI33, but it is no longer being developed or supported.

  7. WebDAV - deprecated.

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

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

  1. 当前首选(Exchange 2013 和 2016)API 是EWS。它完全基于 HTTP,可以从任何语言访问,但有.NetJava特定的库。

    您可以使用EWSEditor来使用 API。

  2. 扩展的 MAPI。这是 Outlook 使用的本机 API。它最终使用MSEMSExchange MAPI 提供程序,它可以使用 RPC(Exchange 2013 不再支持它)或 RPC-over-HTTP(Exchange 2007 或更高版本)或 MAPI-over-HTTP(Exchange 2013 和更高版本)与 Exchange 通信。

    API 本身只能从非托管 C++ 或Delphi访问。您还可以使用Redemption(任何语言)——它的RDO对象系列是一个扩展的 MAPI 包装器。要使用扩展 MAPI,您需要安装 Outlook 或MAPI独立 (Exchange) 版本(在扩展支持下,它不支持 Unicode PST 和 MSG 文件并且无法访问 Exchange 2016)。扩展的 MAPI 可以在服务中使用。

    您可以使用OutlookSpyMFCMAPI来使用 API 。

  3. Outlook 对象模型- 不是特定于 Exchange 的,但它允许访问运行代码的机器上 Outlook 中的所有可用数据。不能在服务中使用。

  4. 交换主动同步。Microsoft 不再向该协议投入任何大量资源。

  5. Outlook 曾经安装 CDO 1.21 库(它封装了扩展 MAPI),但它已被 Microsoft 弃用,不再接收任何更新。

  6. 曾经有一个名为 MAPI33 的第三方 .Net MAPI 包装器,但它不再被开发或支持。

  7. WebDAV - 已弃用。

  8. Exchange 协作数据对象 (CDOEX) - 已弃用。

  9. Exchange OLE DB 提供程序 (EXOLEDB) - 已弃用。