Đọc email MS Exchange trong C #


91

Tôi cần khả năng giám sát và đọc e-mail từ một hộp thư cụ thể trên Máy chủ MS Exchange (nội bộ của công ty tôi). Tôi cũng cần có khả năng đọc địa chỉ e-mail, chủ đề, nội dung thư của người gửi và tải xuống tệp đính kèm, nếu có.

Cách tốt nhất để thực hiện việc này bằng C # (hoặc VB.NET) là gì?


4
Kể từ đó, Microsoft đã phát hành Exchange Web Services Managed API cho Exchange 2007 SP1 và v2010, cho phép người dùng truy cập theo chương trình vào hộp thư của bạn mà không cần Outlook. Tôi có hai bài viết trên blog của mình thảo luận về cách tiếp cận này: - C #: Nhận tất cả email từ Exchange bằng Exchange Web Services
ΩmegaMan

Exchange Web Services Managed API 1.0 SDK là phương pháp được khuyến nghị của Microsoft để cập nhật Exchange theo chương trình cho Exchange Server 2007 SP1 trở lên. msdn.microsoft.com/en-us/library/dd633710(EXCHG.80).aspx
jlo Ngày

Câu trả lời:


90

Đó là một mớ hỗn độn. MAPI hoặc CDO thông qua một DLL tương tác .NET chính thức không được Microsoft hỗ trợ - nó có vẻ hoạt động tốt, nhưng có vấn đề với rò rỉ bộ nhớ do các kiểu bộ nhớ khác nhau của chúng. Bạn có thể sử dụng CDOEX, nhưng điều đó chỉ hoạt động trên chính máy chủ Exchange, không hoạt động từ xa; vô ích. Bạn có thể tương tác với Outlook, nhưng bây giờ bạn vừa phụ thuộc vào Outlook; quá mức cần thiết. Cuối cùng, bạn có thể sử dụng hỗ trợ WebDAV của Exchange 2003 , nhưng WebDAV phức tạp, .NET có hỗ trợ tích hợp kém cho nó và (thêm vào đó là tổn thương) Exchange 2007 gần như hoàn toàn không hỗ trợ WebDAV.

Một chàng trai phải làm gì? Tôi đã kết thúc bằng cách sử dụng thành phần IMAP của AfterLogic để giao tiếp với máy chủ Exchange 2003 của mình qua IMAP và điều này đã hoạt động rất tốt. (Tôi thường tìm kiếm các thư viện mã nguồn mở hoặc miễn phí, nhưng tôi thấy tất cả các thư viện .NET đều mong muốn - đặc biệt là khi nói đến một số điểm kỳ quặc của việc triển khai IMAP của năm 2003 - và cái này đủ rẻ và hoạt động trên cơ sở đầu tiên cố gắng. Tôi biết có những người khác ngoài đó.)

Tuy nhiên, nếu tổ chức của bạn đang sử dụng Exchange 2007 thì bạn đang gặp may. Exchange 2007 đi kèm với giao diện dịch vụ Web dựa trên SOAP cuối cùng cung cấp một cách thức tương tác thống nhất, không phụ thuộc vào ngôn ngữ với máy chủ Exchange. Nếu bạn có thể đặt 2007+ trở thành một yêu cầu, thì đây chắc chắn là cách tốt nhất. (Thật đáng buồn cho tôi, công ty của tôi có chính sách "nhưng năm 2003 không bị phá vỡ".)

Nếu bạn cần kết nối cả Exchange 2003 và 2007, IMAP hoặc POP3 chắc chắn là lựa chọn phù hợp.


21
Dịch vụ web dựa trên SOAP đã được Microsoft bao bọc để đơn giản hóa việc truy cập - hiện nay bạn nên sử dụng SDK 1.0 của Exchange Web Services Managed API: msdn.microsoft.com/en-us/library/dd633710(EXCHG.80).aspx
jlo

4
Nó gần như là nếu Microsoft thiết kế nó để thể không hoạt động với bất cứ điều gì nhưng Outlook
Chris S

67

Ừm,

Tôi có thể hơi muộn ở đây nhưng đây không phải là điểm đến của EWS sao?

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

Mất khoảng 6 dòng mã để nhận thư từ hộp thư:

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
"Các EWS Managed API đơn giản hoá việc triển khai các ứng dụng giao tiếp với Microsoft Exchange Server 2007 Service Pack 1 (SP1) và các phiên bản sau này của Microsoft Exchange"
Chris S

2
Nhận ra rằng đây thực chất là một đoạn mã chết cho một tin nhắn cũ, nhưng đoạn mã này đã giúp tôi thiết lập và chạy một dự án tương tự trong khoảng năm phút. Làm việc hoàn hảo ngay từ lần đầu tiên. Thực sự là một giải pháp hiện đại / toàn diện hơn câu trả lời đã chọn IMO ... cần lưu ý cho bất kỳ ai khác tham khảo.
David W

2
Lưu ý về việc chạy này. Bạn cần cài đặt gói NuGet "Microsoft Exchange WebServices"
John M

4
Điều này đã làm việc cho tôi trong lần thử đầu tiên. Đây phải là câu trả lời mới được chấp nhận.
kroe761

Tôi có thể biết nếu tôi sử dụng một địa chỉ email ngoài hộp thư của riêng service.autodiscoverurltôi, tôi sẽ cần phải nhập service.credentials, tôi có đúng không?
mã phòng tập vào

19
  1. API hiện được ưa thích (Exchange 2013 và 2016) là EWS . Nó hoàn toàn dựa trên HTTP và có thể được truy cập từ bất kỳ ngôn ngữ nào, nhưng có các thư viện .NetJava cụ thể.

    Bạn có thể sử dụng EWSEditor để chơi với API.

  2. MAPI mở rộng . Đây là API gốc được Outlook sử dụng. Nó kết thúc bằng cách sử dụng MSEMSnhà cung cấp Exchange MAPI, có thể nói chuyện với Exchange bằng RPC (Exchange 2013 không còn hỗ trợ nó) hoặc RPC-over-HTTP (Exchange 2007 hoặc mới hơn) hoặc MAPI-over-HTTP (Exchange 2013 và mới hơn).

    Bản thân API chỉ có thể được truy cập từ C ++ hoặc Delphi không được quản lý . Bạn cũng có thể sử dụng Redemption (bất kỳ ngôn ngữ nào) - họ đối tượng RDO của nó là một trình bao bọc MAPI Mở rộng. Để sử dụng MAPI Mở rộng, bạn cần cài đặt Outlook hoặc phiên bản độc lập (Exchange) của MAPI (trên hỗ trợ mở rộng và nó không hỗ trợ tệp Unicode PST và MSG và không thể truy cập Exchange 2016). MAPI mở rộng có thể được sử dụng trong một dịch vụ.

    Bạn có thể chơi với API bằng OutlookSpy hoặc MFCMAPI .

  3. Mô hình đối tượng Outlook - không dành riêng cho Exchange, nhưng nó cho phép truy cập vào tất cả dữ liệu có sẵn trong Outlook trên máy chạy mã. Không thể được sử dụng trong một dịch vụ.

  4. Exchange Active Sync . Microsoft không còn đầu tư bất kỳ nguồn lực đáng kể nào vào giao thức này.

  5. Outlook được sử dụng để cài đặt thư viện CDO 1.21 (nó bao bọc MAPI Mở rộng), nhưng nó đã bị Microsoft không dùng nữa và không còn nhận được bất kỳ bản cập nhật nào nữa.

  6. Đã từng có trình bao bọc .Net MAPI của bên thứ ba được gọi là MAPI33, nhưng nó không còn được phát triển hoặc hỗ trợ nữa.

  7. WebDAV - không dùng nữa.

  8. Đối tượng dữ liệu cộng tác cho Exchange (CDOEX) - không được dùng nữa.

  9. Nhà cung cấp Exchange OLE DB (EXOLEDB) - không được dùng nữa.


EwsEditor đã chuyển sang github: github.com/dseph/EwsEditor
Opmet

10

Đây là một số mã cũ tôi đã đặt xung quanh để làm WebDAV. Tôi nghĩ nó được viết dựa trên Exchange 2003, nhưng tôi không nhớ nữa. Hãy mượn nó nếu nó hữu ích ...

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

Và mô hình.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
LƯU Ý: Hỗ trợ WebDAV bị loại bỏ khỏi Exchange Server 2010, hãy sử dụng EWS để thay thế.
Người đàn ông trong chuối của chúng ta vào


0

Nếu máy chủ Exchange của bạn được định cấu hình để hỗ trợ POP hoặc IMAP, đó là một cách dễ dàng.

Một tùy chọn khác là truy cập WebDAV. có một thư viện có sẵn cho điều đó. Đây có thể là lựa chọn tốt nhất của bạn.

Tôi nghĩ rằng có các tùy chọn sử dụng đối tượng COM để truy cập Exchange, nhưng tôi không chắc nó dễ dàng như thế nào.

Tất cả phụ thuộc vào chính xác những gì quản trị viên của bạn sẵn sàng cấp cho bạn quyền truy cập, tôi đoán.


0

Bạn sẽ có thể sử dụng MAPI để truy cập hộp thư và lấy thông tin bạn cần. Thật không may, thư viện .NET MAPI duy nhất (MAPI33) mà tôi biết dường như không có gì lạ. Đây từng là một cách tuyệt vời để truy cập MAPI thông qua .NET, nhưng tôi không thể nói về hiệu quả của nó bây giờ. Có thêm thông tin về nơi bạn có thể lấy nó ở đây: Vị trí tải xuống cho MAPI33.dll?



0

Một tùy chọn là sử dụng Outlook. Chúng tôi có một ứng dụng quản lý thư truy cập một máy chủ trao đổi và sử dụng outlook làm giao diện. Nó bẩn nhưng nó hoạt động.

Mã ví dụ:

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
Nếu tôi muốn sử dụng Windows Service trong Win2003 để truy cập vào Exchange 2003 ?? Tôi cần cài đặt Outlook 2003 hoặc 2007 trong Server win2003?
Kiquenet
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.