使用C#阅读MS Exchange电子邮件


91

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

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


4
此后,Microsoft已发布了适用于Exchange 2007 SP1和v2010的Exchange Web服务托管API,该API可通过编程方式进入您的邮箱,而无需使用Outlook。我的博客上有两篇文章讨论了这种方法:-C#:使用Exchange Web服务从Exchange获取所有电子邮件
–ΩmegaMan2010年

Exchange Web服务托管API 1.0 SDK是Microsoft推荐的方法,用于以编程方式为Exchange Server 2007 SP1及更高版本更新Exchange。 msdn.microsoft.com/zh-CN/library/dd633710(EXCHG.80).aspx
2010年

Answers:


90

一团糟。Microsoft官方不支持通过 .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。


21
Microsoft打包了基于SOAP的Web服务以简化访问-现在建议实践使用Exchange Web Services托管API 1.0 SDK: msdn.microsoft.com/zh-cn/library/dd633710(EXCHG.80).aspx
jlo 2010年

4
这是几乎一样,如果微软设计它是不可操作的任何东西,但展望
克里斯小号

67

我在这里可能为时已晚,但这不是EWS的重点吗?

https://msdn.microsoft.com/zh-CN/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
“ EWS托管API简化了与Microsoft Exchange Server 2007 Service Pack 1(SP1)和更高版本的Microsoft Exchange通信的应用程序的实现”
Chris S

2
意识到这从本质上来说已经是一个已有很长时间的信息的坏处了,但是这段代码让我在大约五分钟的时间内启动并运行了一个类似的项目。第一次完美运行。确实比IMO选择的答案更现代/更全面的解决方案...供其他人参考。
David W

2
请注意此运行。您需要安装NuGet软件包“ Microsoft Exchange WebServices”
John M

4
第一次尝试对我有用。这应该是新接受的答案。
kroe761 '19

我可以知道是否要在自己的邮箱之外使用电子邮件地址service.autodiscoverurl,我需要输入service.credentials,对吗?
Gymcode '19

19
  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对象系列是Extended MAPI包装器。若要使用扩展MAPI,您需要安装Outlook或MAPI独立(Exchange)版本(在扩展支持上,它不支持Unicode PST和MSG文件,并且无法访问Exchange 2016)。扩展MAPI可以在服务中使用。

    您可以使用OutlookSpyMFCMAPI来使用API 。

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

  4. 交换活动同步。Microsoft不再在此协议上投入大量资源。

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

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

  7. WebDAV-已弃用。

  8. Exchange协作数据对象(CDOEX)-已过时。

  9. Exchange OLE DB提供程序(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;
    }
}

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

1
注意:WebDAV支持已从Exchange Server 2010中删除,请改用EWS。
我们在香蕉里的人2014年


0

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

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

我认为有一些使用COM对象访问Exchange的选项,但是我不确定它有多简单。

这全取决于您的管理员愿意为您提供访问权限的确切程度。


0

您应该能够使用MAPI访问邮箱并获取所需的信息。不幸的是,我所知道的唯一.NET MAPI库(MAPI33)似乎无法维护。这曾经是通过.NET访问MAPI的好方法,但是我现在不能说它的有效性。有关在哪里可以找到它的更多信息: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
如果要在Win2003中使用Windows Service访问Exchange 2003?我需要在Server win2003中安装Outlook 2003或2007吗?
Kiquenet
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.