用 C# 读取 MS Exchange 电子邮件

发布于 2024-07-15 02:37:50 字数 134 浏览 3 评论 0 原文

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

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

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.

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

素衣风尘叹 2024-07-22 02:37:50

一团糟。 通过 .NET 互操作 DLL 的 MAPI 或 CDO 为 微软官方不支持——它看起来工作正常,但由于它们的内存不同,存在内存泄漏的问题楷模。 您可以使用 CDOEX,但它只能在 Exchange 服务器本身上运行,不能远程运行; 无用。 您可以与 Outlook 进行互操作,但现在您只是建立了对 Outlook 的依赖; 矫枉过正。 最后,您可以使用 Exchange 2003 的 WebDAV 支持,但 WebDAV 很复杂, .NET 对其的内置支持很差,并且(雪上加霜)Exchange 2007 几乎完全放弃了 WebDAV 支持。

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

但是,如果您的组织使用的是 Exchange 2007,那么您很幸运。 Exchange 2007 附带了基于 SOAP 的 Web 服务接口,该接口最终提供了与 Exchange 服务器交互的统一的、独立于语言的方式。 如果您可以将 2007+ 作为一个要求,那么这绝对是您的最佳选择。 (对我来说不幸的是,我的公司有一个“但 2003 没有被破坏”的政策。)

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

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 drops WebDAV support.

What's a guy to do? I ended up using AfterLogic's IMAP component to 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.)

If your organization is on Exchange 2007, however, you're in luck. Exchange 2007 comes with a SOAP-based Web service interface that 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.)

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

屋檐 2024-07-22 02:37:50

嗯,

我可能有点太晚了,但这不是 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( "[email protected]" );

FindItemsResults<Item> findResults = service.FindItems(
   WellKnownFolderName.Inbox,
   new ItemView( 10 ) 
);

foreach ( Item item in findResults.Items )
{
   Console.WriteLine( item.Subject );
}

Um,

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

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

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

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 );
}
烟柳画桥 2024-07-22 02:37:50
  1. Graph - 目前首选的统一 API(基于纯 HTTP)访问驻留在 Exchange Server 上的电子邮件、联系人、约会、任务等以及 Microsoft 托管的其他数据(Teams、Sharepoint 等)。
    使用 Graph ExplorerOutlookSpy(我是它的作者)来使用 API。
    Microsoft 提供Graph SDK,供多种语言使用

  2. EWS。 完全支持。 它纯粹基于 HTTP,可以从任何语言访问,但有 .NetJava 特定库。
    MS 表示不会添加新功能,并且 Graph 更可取,尽管并非所有 EWS 功能都可以在 Graph 中使用(例如通过 导出项目/导入项目)。
    您可以使用 EWSEditorOutlookSpy(我是它的作者)来使用 API。

  3. 扩展 MAPI。 这是 Outlook 使用的本机 API。 它最终使用 MSEMS Exchange MAPI 提供程序,该提供程序可以使用 RPC(Exchange 2013 不再支持它)或 RPC-over-HTTP(Exchange 2007 或更高版本)或 MAPI-over-HTTP 与 Exchange 通信(Exchange 2013 及更高版本)。
    API 本身只能从非托管 C++ 或 Delphi 访问。 您还可以使用 Redemption (任何语言,我是它的作者) - 它的 RDO 对象系列是扩展 MAPI 包装器。 要使用扩展 MAPI,您需要安装 Outlook 或独立版(Exchange) 版本的 MAPI(扩展支持,不支持 Unicode PST 和 MSG 文件,并且无法访问 Exchange 2016)。 扩展 MAPI 可以在服务中使用。
    您可以使用 OutlookSpy (我是其作者)或 MFCMAPI

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

  5. Exchange Active 同步。 Microsoft 不再为此协议投入任何大量资源。

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

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

  8. WebDAV - 已弃用。

  9. 协作数据对象交换 (CDOEX) - 已弃用。

  10. 交换 OLE DB 提供程序 (EXOLEDB) - 已弃用。

  1. Graph - currently, the preferred unified API (pure HTTP based) to access emails, contacts, appointments, tasks etc., residing on Exchange Server along with other data hosted by Microsoft (Teams, Sharepoint, etc.).
    Use Graph Explorer or OutlookSpy (I am its author) to play with the API.
    Microsoft provides Graph SDK for use in several languages

  2. EWS. Fully supported. It is purely HTTP based and can be accessed from any language, but there are .Net and Java specific libraries.
    MS has indicated that no new features will be added, and that Graph is preferable, even though not all EWS features are yet available in Graph (such as high fidelity Fast Transfer Stream export/import exposed through ExportItems/ImportItems).
    You can use EWSEditor or OutlookSpy (I am its author) to play with the API.

  3. Extended MAPI. This is the native API used by Outlook. It ends up using the MSEMS Exchange 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, I am its author) - its RDO family 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 OutlookSpy (I am its author) or MFCMAPI.

  4. 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.

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

  6. 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.

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

  8. WebDAV - deprecated.

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

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

夜空下最亮的亮点 2024-07-22 02:37:50

这是我用来执行 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;
    }
}

以及型号。邮件:

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

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...

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:

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; }
    }
}
沉默的熊 2024-07-22 02:37:50

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

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.

输什么也不输骨气 2024-07-22 02:37:50

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

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

我认为可以选择使用 COM 对象来访问 Exchange,但我不确定它有多容易。

我想,这完全取决于您的管理员愿意向您授予哪些访问权限。

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

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

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

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

凯凯我们等你回来 2024-07-22 02:37:50

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

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?

尸血腥色 2024-07-22 02:37:50

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

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文