<form id="hz9zz"></form>
  • <form id="hz9zz"></form>

      <nobr id="hz9zz"></nobr>

      <form id="hz9zz"></form>

    1. 明輝手游網中心:是一個免費提供流行視頻軟件教程、在線學習分享的學習平臺!

      用C#訪問Hotmail

      [摘要]作者:仙人掌工作室   POP郵件協議的優點在于它是一個開放的標準,有著完善的文檔,這就使得編寫POP郵件客戶程序不那么困難,只要掌握了POP、SMTP的基礎知識,就可以寫出代理程序來執行各種任務,...
      作者:仙人掌工作室

        POP郵件協議的優點在于它是一個開放的標準,有著完善的文檔,這就使得編寫POP郵件客戶程序不那么困難,只要掌握了POP、SMTP的基礎知識,就可以寫出代理程序來執行各種任務,例如過濾廣告和垃圾郵件,或提供e-mail自動應答服務。

        Hotmail是世界上影響最廣的Web郵件系統,遺憾的是,當我們要為Hotmail編寫獨立的客戶程序(不通過瀏覽器訪問的客戶程序)時,馬上就會遇到Hotmail不提供POP網關這一障礙。

        雖然Hotmail不提供POP支持,但瀏覽器并非訪問Hotmail的唯一途徑。例如,利用Outlook Express可以直接連接到標準的Hotmail或MSN信箱,提取、刪除、移動或發送郵件。利用HTTP包監視器,我們可以監視到Outlook Express和Hotmail的通信過程,分析出客戶程序如何連接到Hotmail信箱。

        Outlook Express利用了一種通常稱為HTTPMail的未公開的協議,借助一組HTTP/1.1擴展訪問Hotmail。本文將介紹HTTPMail的一些特點以及利用C#客戶程序訪問Hotmail的過程。本文的示例程序利用COM互操作將XMLHTTP用作一種傳輸服務。XMLHTTP組件提供了一個完善的HTTP實現,除了包括認證功能,還能夠在發送HTTP請求給服務器之前設置定制的HTTP頭。

        一、連接HTTPMail網關

        Hotmail信箱默認的HTTPMail網關在http://services.msn.com/svcs/hotmail/httpmail.asp。HTTPMail協議實際上是一個標準的WebDAV服務,只不過尚未公開而已。在編寫C#程序時,我們可以方便地調用.NET框架在System.Net名稱空間中提供的各個TCP和HTTP類。另外,由于我們要操作WebDAV,在C#環境下利用XMLHTTP連接Hotmail最為簡便,只需引用一下MSXML2組件就可以直接訪問。注意在本文的代碼片斷中,帶有下滑線后綴的變量是示例代碼中聲明的成員域:

      // 獲得名稱空間
        using MSXML2;
        ...
        // 創建對象
        xmlHttp_ = new XMLHTTP();



        為了連接到安全服務器,WebDAV協議要求執行HTTP/1.1驗證。HTTPMail客戶程序發出的第一個請求利用WebDAV PROPFIND方法查找一組屬性,其中包括Hotmail廣告條的URL以及信箱文件夾的位置:

      <?xml version="1.0"?>
        <D:propfind xmlns:D="DAV:" xmlns:h="http://schemas.microsoft.com/hotmail/"
      xmlns:hm="urn:schemas:httpmail:">
          <D:prop>
            <h:adbar/>
            <hm:contacts/>
            <hm:inbox/>
            <hm:outbox/>
            <hm:sendmsg/>
            <hm:sentitems/>
            <hm:deleteditems/>
            <hm:drafts/>
            <hm:msgfolderroot/>
            <h:maxpoll/>
            <h:sig/>
          </D:prop>
        </D:propfind>



        通過XMLHTTP發送第一個請求時,首先指定WebDAV服務器URL,然后生成XML請求的內容:

      // 指定服務器的URL
        string serverUrl = "http://services.msn.com/svcs/hotmail/httpmail.asp";
        // 構造查詢
        string folderQuery = null;
        folderQuery += "<?xml version='1.0'?><D:propfind xmlns:D='DAV:' ";
        folderQuery += "xmlns:h='http://schemas.microsoft.com/hotmail/' ";
        folderQuery += "xmlns:hm='urn:schemas:httpmail:'><D:prop><h:adbar/>";
        folderQuery += "<hm:contacts/><hm:inbox/><hm:outbox/><hm:sendmsg/>";
        folderQuery += "<hm:sentitems/><hm:deleteditems/><hm:drafts/>";
        folderQuery += "<hm:msgfolderroot/><h:maxpoll/><h:sig/></D:prop></D:propfind>";



        XMLHTTP組件提供了一個open()方法來建立與HTTP服務器的連接:

      void open(string method, string url, bool async, string user, string password);



        open()方法的第一個參數指定了用來打開連接的HTTP方法,例如GET、POST、PUT或PROPFIND,通過這些HTTP方法我們可以提取文件夾信息、收集郵件或發送新郵件。為連接到Hotmail網關,我們指定用PROPFIND方法來查詢信箱。注意open()方法允許執行異步調用(默認啟用),對于帶圖形用戶界面的郵件客戶程序來說,異步調用是最理想的調用方式。由于本文的示例程序是一個控制臺應用,我們把這個參數設置成false。

        為了執行身份驗證,我們在open()方法中指定了用戶名字和密碼。在使用XMLHTTP組件時,如果open()方法沒有提供用戶名字和密碼參數,但網站要求執行身份驗證,XMLHTTP將顯示出一個登錄窗口。為了打開通向Hotmail網關的連接,我們把PROPFIND請求的頭設置成XML查詢的內容,消息的正文保持空白,然后發送消息:

      // 打開一個通向Hotmail服務器的連接
        xmlHttp_.open("PROPFIND", serverUrl, false, username, password);
        // 發送請求
        xmlHttp_.setRequestHeader("PROPFIND", folderQuery);
        xmlHttp_.send(null);



        二、分析信箱的文件夾列表

        發送給services.msn.com的請求通常要經歷幾次重定向,經過服務器端的負載平衡處理,最后請求會被傳遞到一個空閑的Hotmail服務器,并執行身份驗證。在客戶端,這個重定向、執行身份驗證的交互過程由XMLHTTP組件負責處理。成功建立連接后,服務器還會要求設置一些Cookie、驗證當前會話的合法性,這部分工作同樣也由XMLHTTP組件自動處理。初始的連接請求發出之后,服務器將返回一個XML格式的應答:

      // 獲得應答的內容
        string folderList = xmlHttp_.responseText;



        服務器返回的應答包含許多有用的信息,其中包括信箱中文件夾的URL位置,下面是一個例子:

      <?xml version="1.0" encoding="Windows-1252"?>
          <D:response>
            ...
            <D:propstat>
              <D:prop>
                <h:adbar>AdPane=Off*...</h:adbar>
                <hm:contacts>http://law15.oe.hotmail.com/...</hm:contacts>
                <hm:inbox>http://law15.oe.hotmail.com/...</hm:inbox>
                <hm:sendmsg>http://law15.oe.hotmail.com/...</hm:sendmsg>
                <hm:sentitems>http://law15.oe.hotmail.com/...</hm:sentitems>
                <hm:deleteditems>http://law15.oe.hotmail.com/...</hm:deleteditems>
                <hm:msgfolderroot>http://law15.oe.hotmail.com/...</hm:msgfolderroot>
                ...
             </D:prop>
           </D:response>
        </D:multistatus>



        在本文的控制臺示例程序中,我們感興趣的兩個文件夾是收件箱和發件箱的文件夾,它們分別用于接收和發送郵件。

        在C#環境中解析XML的方法很多,由于我們肯定代碼涉及的所有XML文檔總是合法的,所以可以利用System.XML.XmlTextReader速度快的優勢。XmlTextReader是一個“只向前”的讀取器,下面把XML字符數據轉換成字符流,初始化XML讀取器:

      // 初始化
        inboxUrl_ = null;
        sendUrl_ = null;
        // 裝入XML
        StringReader reader = new StringReader(folderList);
        XmlTextReader xml = new XmlTextReader(reader);



        遍歷各個節點,選取出hm:inbox和hm:sendmsg節點,這兩個節點分別代表收件箱和發件箱:

      // 讀取XML數據
        while(xml.Read())
        {
          // 是一個XML元素?
          if(xml.NodeType == XmlNodeType.Element)
          {
            // 獲取該節點
            string name = xml.Name;
            // 該節點代表收件箱?
            if(name == "hm:inbox")
            {
              // 保存收件箱URL
              xml.Read();
              inboxUrl_ = xml.Value;
            }
            // 該節點代表發件箱?
            if(name == "hm:sendmsg")
            {
              // 保存發件箱URL
              xml.Read();
              sendUrl_ = xml.Value;
            }
          }
        }



        只有先獲取當前這次會話的合法的收件箱和發件箱URL,才可以發送和接收郵件。

        三、列舉文件夾內容

        得到了信箱文件夾(如收件箱)的URL之后,就可以向該文件夾的URL發送WebDAV請求列舉其內容。示例程序定義了一個托管類型MailItem,用來保存文件夾里一項內容(即一個郵件)的信息。文件夾內容列舉從初始化一個MailItems數組開始:

      // 初始化
        ArrayList mailItems = new ArrayList();



        為獲得郵件主題、收件人地址、發件人地址之類的郵件基本信息,我們要用到下面XML格式的WebDAV查詢:

      <?xml version="1.0"?>
        <D:propfind xmlns:D="DAV:" xmlns:hm="urn:schemas:httpmail:" xmlns:m="
         urn:schemas:mailheader:">
          <D:prop>
            <D:isfolder/>
            <hm:read/>
            <m:hasattachment/>
            <m:to/>
            <m:from/>
            <m:subject/>
            <m:date/>
            <D:getcontentlength/>
          </D:prop>
        </D:propfind>



        生成上述XML查詢字符串的C#代碼:

      // 構造查詢
        string getMailQuery = null;
        getMailQuery += "<?xml version='1.0'?><D:propfind xmlns:D='DAV:' ";
        getMailQuery += "xmlns:hm='urn:schemas:httpmail:' ";
        getMailQuery += "xmlns:m='urn:schemas:mailheader:'><D:prop><D:isfolder/>";
        getMailQuery += "<hm:read/><m:hasattachment/><m:to/><m:from/><m:subject/>";
        getMailQuery += "<m:date/><D:getcontentlength/></D:prop></D:propfind>";



        就象前面獲取信箱文件夾清單的方式一樣,上述請求也通過XMLHTTP用PROPFIND方法發送,這次我們把請求的正文設置成查詢字符串。由于當前會話的用戶身份已經通過驗證,所以XMLHTTP open()調用中不必再提供用戶名字和密碼:

      // 獲取郵件信息
        xmlHttp_.open("PROPFIND", folderUrl, false, null, null);
        xmlHttp_.send(getMailQuery);
        string folderInfo = xmlHttp_.responseText;



        如果請求成功,服務器返回的應答XML流包含了該文件夾中各個郵件的信息:

      <D:multistatus>
          <D:response>
            <D:href>
              http://sea1.oe.hotmail.com/cgi-bin/hmdata/...
            </D:href>
            <D:propstat>
              <D:prop>
                <hm:read>1</hm:read>
                <m:to/>
                <m:from>Mark Anderson</m:from>
                <m:subject>RE: New Information</m:subject>
                <m:date>2002-08-06T16:38:39</m:date>
                <D:getcontentlength>1238</D:getcontentlength>
              </D:prop>
              <D:status>HTTP/1.1 200 OK</D:status>
            </D:propstat>
          </D:response>
          ...



        觀察服務器返回的應答,我們發現每一個節點包含一組標識郵件的域,例如通過標記可提取出郵件。下面我們再次使用System.XML.XmlTextReader解析這個XML數據流,首先初始化流讀取器:

      MailItem mailItem = null;

        // 裝入XML
        StringReader reader = new StringReader(folderInfo);
        XmlTextReader xml = new XmlTextReader(reader);



        四、分析郵件基本信息

        為了遍歷一次就解析好整個XML文檔,我們在每次打開元素時就創建一個新的MailItem實例,一遇到標記的末尾就保存該實例,在此期間,我們提取并設置MailItem的域:

      // 讀取XML數據
        while(xml.Read())
        {
          string name = xml.Name;
          XmlNodeType nodeType = xml.NodeType;
          // 是一個email?
          if(name == "D:response")
          {
              // 開始?
              if(nodeType == XmlNodeType.Element)
              {
                // 創建一個新的MailItem
                mailItem = new MailItem();
              }
              // 結束?
              if(nodeType == XmlNodeType.EndElement)
              {
                // 保存email
                mailItems.Add(mailItem);
                // 清除變量
                mailItem = null;
              }
            }

            // 是一個元素?
            if(nodeType == XmlNodeType.Element)
            {
              // 郵件的URL屬性
              if(name == "D:href")
              {
                // 繼續讀取
                xml.Read();
                mailItem.Url = xml.Value;
              }

              // 郵件的“已閱讀”屬性
              if(name == "hm:read")
              {
                // 繼續讀取
                xml.Read();
                mailItem.IsRead = (xml.Value == "1");
              }

              // 其他MailItem的屬性...
            }
          }



        上面的代碼枚舉指定文件夾內的每一個MailItem,分別提取各個MailItem的下列屬性:

      XML節點  說明  
      D:href  用來提取郵件的URL  
      hm:read  如果郵件已閱讀,則該標記被設置  
      m:to  收件人  
      m:from  發件人  
      m:subject  郵件主題  
      m:date  時間標記  
      D:getcontentlength  郵件的大。ㄗ止潝担



        五、接收郵件

        枚舉出文件夾里面的MailItem之后,我們就可以利用MailItem的URL獲得郵件本身,只需要向Hotmail服務器發送一個HTTP/1.1 GET請求就可以了。示例代碼中的LoadMail()函數輸入一個MailItem實例作為參數,返回郵件的內容:

      /// <summary>
        /// 下載MailItem指定的郵件
        /// </summary>
        public string LoadMail(MailItem mailItem)
        {
          // 郵件的URL
          string mailUrl = mailItem.Url;
          // 打開Hotmail服務器連接
          xmlHttp_.open("GET", mailUrl, false, null, null);
          // 發送請求
          xmlHttp_.send(null);
          // 獲取應答
          string mailData = xmlHttp_.responseText;
          // 返回郵件數據
          return mailData;
        }



        六、發送郵件

        LoadMail()方法通過發送HTTP/1.1 GET請求獲取郵件,類似地,用Hotmail發件箱發送郵件時我們提交一個POST請求,如下面的SendMail()方法所示。

      /// <summary>
        /// 發送一個郵件
        /// </summary>
        public void SendMail(string from, string fromName,
          string to, string subject, string body)
        {
          ...
        }



        首先準備好后面要用到的引號字符以及郵件的時間標記:

      // 引號字符
        string quote = "\u0022";

        // 時間標記
        DateTime now = DateTime.Now;
        string timeStamp = now.ToString("ddd, dd MMM yyyy hh:mm:ss");



        HTTPMail協議采用與SMTP相似的通信模式。Outlook Express用MIME格式發送郵件,但為簡單計,本例我們只發送純文本的郵件:

      // 構造POST請求的內容
        string postBody = null;
        // 郵件頭.
        postBody += "MAIL FROM:<" + from + ">\r\n";
        postBody += "RCPT TO:<" + to + ">\r\n";
        postBody += "\r\n";
        postBody += "From: " + quote + fromName + quote + " <" + from + ">\r\n";
        postBody += "To: <" + to + ">\r\n";
        postBody += "Subject: " + subject +"\r\n";
        postBody += "Date: " + timeStamp + " -0000\n";
        postBody += "\r\n";
        // 郵件正文
        postBody += body;



        發送郵件時,我們要把Content-Type請求頭設置成message/rfc821,表示這個請求包含一個遵從RFC821的消息。最后要做的就是把郵件發送到服務器:

      // 打開連接
        xmlHttp_.open("POST", sendUrl_, false, null, null);
        // 發送請求
        xmlHttp_.setRequestHeader("Content-Type", "message/rfc821");
        xmlHttp_.send(postBody);



        只要目標地址正確無誤,Hotmail就會把郵件發送到目的地。

        結束語:

        Hotmail是世界上最大的免費Web郵件提供商。但是,Hotmail使用的HTTPMail協議是非公開的,從而為編寫直接訪問Hotmail的客戶程序帶來了困難。本文示范了如何在C#環境中利用XMLHTTP組件直接連接到Hotmail,以及如何發送和接收郵件,證明了通過HTTPMail連接Hotmail可以做到象使用POP3、IMAP4、SMTP等協議一樣簡單。  



      日韩精品一区二区三区高清