国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 開發 > 綜合 > 正文

用C#訪問Hotmail

2024-07-21 02:17:21
字體:
來源:轉載
供稿:網友
  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等協議一樣簡單。

代碼下載地址:http://www.webasp.net/tech/download_show.asp?id=377


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 淮南市| 申扎县| 东丰县| 永嘉县| 保康县| 贵州省| 海原县| 舞阳县| 苏州市| 西畴县| 荥阳市| 辉南县| 平原县| 达日县| 金华市| 江油市| 奉化市| 恩施市| 麻城市| 蕉岭县| 台北市| 长子县| 涿州市| 高邑县| 三明市| 夏津县| 建德市| 瑞丽市| 玛多县| 美姑县| 鄂州市| 高雄县| 错那县| 平湖市| 中方县| 蓬溪县| 濮阳县| 江永县| 绥中县| 克山县| 大同市|