อ่านอีเมล MS Exchange ใน C #


91

ฉันต้องการความสามารถในการตรวจสอบและอ่านอีเมลจากกล่องจดหมายเฉพาะบน MS Exchange Server (ภายใน บริษัท ของฉัน) ฉันยังต้องสามารถอ่านที่อยู่อีเมลของผู้ส่งหัวเรื่องเนื้อหาข้อความและดาวน์โหลดไฟล์แนบถ้ามี

วิธีที่ดีที่สุดในการทำเช่นนี้โดยใช้ C # (หรือ VB.NET) คืออะไร?


4
Microsoft ได้เปิดตัว Exchange Web Services Managed API สำหรับ Exchange 2007 SP1 และ v2010 ซึ่งช่วยให้สามารถเข้าถึงกล่องจดหมายของคุณโดยใช้โปรแกรมได้โดยไม่ต้องใช้ Outlook ฉันมีบทความสองบทความในบล็อกของฉันซึ่งพูดถึงแนวทางนี้: - C #: การรับอีเมลทั้งหมดจาก Exchange โดยใช้ Exchange Web Services
ΩmegaMan

Exchange Web Services Managed API 1.0 SDK เป็นวิธีการที่ 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 overkill. ในที่สุดคุณสามารถใช้การสนับสนุน WebDAV ของ Exchange 2003แต่ WebDAV มีความซับซ้อน. NET มีการสนับสนุนในตัวที่ไม่ดีและ (เพื่อเพิ่มการดูถูกการบาดเจ็บ) Exchange 2007 เกือบจะยุติการสนับสนุน WebDAV

ผู้ชายจะทำอะไร? ฉันลงเอยด้วยการใช้องค์ประกอบ IMAP ของ AfterLogicเพื่อสื่อสารกับเซิร์ฟเวอร์ Exchange 2003 ของฉันผ่าน IMAP และสิ่งนี้ก็ทำงานได้ดีมาก (โดยปกติฉันจะหาไลบรารีฟรีหรือโอเพ่นซอร์ส แต่ฉันพบว่า. NET ทั้งหมดต้องการ - โดยเฉพาะอย่างยิ่งเมื่อพูดถึงความไม่ชอบมาพากลของการใช้งาน IMAP ในปี 2003 - และอันนี้มีราคาถูกพอและใช้งานได้ในครั้งแรก ลองฉันรู้ว่ามีคนอื่นอยู่ที่นั่น)

อย่างไรก็ตามหากองค์กรของคุณใช้ Exchange 2007 แสดงว่าคุณโชคดี Exchange 2007 มาพร้อมกับอินเทอร์เฟซบริการบนเว็บที่ใช้ SOAPซึ่งในที่สุดก็มีวิธีการโต้ตอบกับเซิร์ฟเวอร์ Exchange ที่เป็นหนึ่งเดียวโดยไม่ขึ้นกับภาษา หากคุณสามารถสร้างข้อกำหนดในปี 2550 ขึ้นไปได้นี่คือหนทางที่จะไปอย่างแน่นอน (น่าเศร้าสำหรับฉัน บริษัท ของฉันมีนโยบาย "but 2003 ไม่เสีย")

หากคุณต้องการเชื่อมต่อทั้ง Exchange 2003 และ 2007 IMAP หรือ POP3 เป็นวิธีที่จะไปได้อย่างแน่นอน


21
บริการเว็บที่ใช้ SOAP ถูกห่อหุ้มโดย Microsoft เพื่อลดความซับซ้อนในการเข้าถึง - ตอนนี้ขอแนะนำให้ใช้ Exchange Web Services Managed API 1.0 SDK: msdn.microsoft.com/en-us/library/dd633710(EXCHG.80).aspx
jlo

4
เกือบจะเหมือนกับว่า Microsoft ออกแบบให้ไม่สามารถใช้งานได้กับทุกสิ่งยกเว้น Outlook
Chris S

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
"EWS Managed 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

ฉันขอทราบได้ไหมว่าฉันจะใช้ที่อยู่อีเมลนอกเหนือจากกล่องจดหมายของตัวเองในservice.autodiscoverurlฉันจะต้องป้อนservice.credentialsฉันถูกไหม
รหัสยิม

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ของออบเจ็กต์คือ Extended MAPI wrapper ในการใช้ Extended MAPI คุณต้องติดตั้งMAPI เวอร์ชัน Outlook หรือเวอร์ชันสแตนด์อโลน (Exchange) (ในการสนับสนุนเพิ่มเติมและไม่รองรับไฟล์ Unicode PST และ MSG และไม่สามารถเข้าถึง Exchange 2016 ได้) Extended MAPI สามารถใช้ในบริการได้

    คุณสามารถเล่นกับ API โดยใช้OutlookSpyหรือMFCMAPI

  3. Outlook Object Model - ไม่ใช่ Exchange เฉพาะ แต่อนุญาตให้เข้าถึงข้อมูลทั้งหมดที่มีอยู่ใน Outlook บนเครื่องที่รหัสทำงาน ไม่สามารถใช้ในบริการได้

  4. แลกเปลี่ยน Active Sync Microsoft ไม่ลงทุนทรัพยากรที่สำคัญใด ๆ ในโปรโตคอลนี้อีกต่อไป

  5. Outlook ใช้ในการติดตั้งไลบรารี CDO 1.21 (ห่อ Extended MAPI) แต่ Microsoft เลิกใช้แล้วและไม่ได้รับการอัปเดตใด ๆ อีกต่อไป

  6. เคยมีกระดาษห่อ. Net MAPI ของ บริษัท อื่นที่เรียกว่า MAPI33 แต่ไม่ได้รับการพัฒนาหรือสนับสนุนอีกต่อไป

  7. WebDAV - เลิกใช้แล้ว

  8. Collaborative Data Objects for Exchange (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;
    }
}

และ 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 แทน
Our Man in Bananas


0

หากเซิร์ฟเวอร์ Exchange ของคุณได้รับการกำหนดค่าให้รองรับ POP หรือ IMAP นั่นเป็นวิธีง่ายๆ

อีกทางเลือกหนึ่งคือการเข้าถึง WebDAV มีห้องสมุดไว้ให้บริการ นี่อาจเป็นตัวเลือกที่ดีที่สุดของคุณ

ฉันคิดว่ามีตัวเลือกโดยใช้วัตถุ COM เพื่อเข้าถึง Exchange แต่ฉันไม่แน่ใจว่ามันง่ายแค่ไหน

ทั้งหมดขึ้นอยู่กับสิ่งที่ผู้ดูแลระบบของคุณเต็มใจให้คุณเข้าถึงฉันเดา


0

คุณควรจะสามารถใช้ MAPI เพื่อเข้าถึงกล่องจดหมายและรับข้อมูลที่คุณต้องการได้ น่าเสียดายที่ไลบรารี. NET MAPI (MAPI33) เดียวที่ฉันรู้ดูเหมือนจะไม่ได้รับการดูแล นี่เคยเป็นวิธีที่ยอดเยี่ยมในการเข้าถึง MAPI ผ่าน. NET แต่ฉันไม่สามารถพูดถึงประสิทธิภาพของมันได้ในตอนนี้ มีข้อมูลเพิ่มเติมเกี่ยวกับตำแหน่งที่คุณสามารถหาได้ที่นี่: ดาวน์โหลดตำแหน่งสำหรับ MAPI33.dll?



0

ทางเลือกหนึ่งคือการใช้ Outlook เรามีแอปพลิเคชันตัวจัดการเมลที่เข้าถึงเซิร์ฟเวอร์ Exchange และใช้ 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 ใน Server win2003 หรือไม่
Kiquenet
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.