欢迎光临
我们一直在努力

用C#访问Hotmail-.NET教程,.NET Framework

建站超值云服务器,限时71元/月

  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

赞(0)
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com 特别注意:本站所有转载文章言论不代表本站观点! 本站所提供的图片等素材,版权归原作者所有,如需使用,请与原作者联系。未经允许不得转载:IDC资讯中心 » 用C#访问Hotmail-.NET教程,.NET Framework
分享到: 更多 (0)