用C#访问Hotmail -转
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请求的内容:
// 指定服务器的URLstring 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;// 装入XMLStringReader 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"){// 保存收件箱URLxml.Read();inboxUrl_ = xml.Value;}// 该节点代表发件箱?if(name == "hm:sendmsg"){// 保存发件箱URLxml.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;// 装入XMLStringReader 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){// 创建一个新的MailItemmailItem = new MailItem();}// 结束?if(nodeType == XmlNodeType.EndElement){// 保存emailmailItems.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){// 邮件的URLstring 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等协议一样简单。
转载于:https://www.cnblogs.com/xioxu/archive/2008/05/06/1185526.html
用C#访问Hotmail -转相关推荐
- 通过JavaMail访问Hotmail邮箱
[size=large]http://blog.csdn.net/changlich/archive/2007/01/01/1472089.aspx 相信许多人都有msn聊天工具的帐号,例如abc@h ...
- 通过JavaMail访问Hotmail邮箱 .
相信许多人都有msn聊天工具的帐号,例如abc@hotmail.com ,这个账号其实也是一个邮件地址,可以进行正常的邮件收发功能,你可以通过网址 http://www.hotmail.com 来访问 ...
- JavaMail 访问Hotmail
Hotmail使用的是WebDAV来提供基于HTTP协议的应用编程接口,WebDAV(Web 分布式创作和版本控制)已经成为重要的 Web 通讯协议.WebDAV所要解决的问题是: 1.改写保护:HT ...
- 使用微软DNS服务器解决Hotmail、微软账户登录页面无法访问的问题
近日,在重装Windows 10系统之后,发现Edge浏览器无法登录微软账号做数据同步,具体表现为登录页面无法打开.此前,通过浏览器访问hotmail等页面的时候,也经常发生页面无法打开或者打开及其缓 ...
- Powershell RESTAPI 访问Office365
豆子之前对Office365的用户操作一般是通过远程的加载模块,然后创建一个session连接. 比如 $cred = Get-Credential Import-Module MSOnline Se ...
- hotmail_在新的Hotmail Wave 4中禁用Messenger
hotmail Are you annoyed by having Messenger automatically sign in when you're reading your emails in ...
- 如何使用SkyDrive的25 GB作为映射驱动器以方便访问
SkyDrive is an online storage system included in Windows Live, which gives you 25 GB of space that y ...
- Java使用hotmail的SMTP服务器转发邮件出错
最近使用hotmail的SMTP在服务器上转发邮件,后台获得如下错误: javax.mail.AuthenticationFailedException: 535 5.0.0 Authenticati ...
- hotmail邮箱不能打开解决方法
hotmail在升级,也有说是由于微软正在宣传新产品WindowsLive系统,所以将所有登陆程序从Passport网站转移到Live网站.由于国内运营商还没有将Live网站加入可访问区域,造成登陆系 ...
最新文章
- 实现php实现价格的排序,php 数组动态添加实现代码(最土团购系统的价格排序)_PHP教程...
- 【数字信号处理】相关系数 ( 相关系数概念解析 | 信号能量常数 | 共轭序列 | 序列在相同时刻的相关性 )
- expdp / impdp 用法详解
- Docker 使用Dockerfile构建Docker(三)
- 韦老师的开发板和嵌入式书籍赠送
- VS2010开发应用程序读写注册表
- Mybatis中#{}与${}的使用
- 很多大企业都在用的Pentaho 商业分析软件中存在多个严重缺陷
- SqlServer-RBAC五表权限
- 嵌入式Ubuntu 搭建caffee环境
- 网页版pdf转换方法
- 愚人节,你的微信公众号图文排版够愚吗?
- VMware Funsion 8.5.1破解版
- java.lang.Byte常用方法
- Python学习:垃圾回收机制
- 国内产线 OLED 良率低,产能释放缓慢
- VisualAssistX无法加载,加载问题异常解决
- 第7章第20节:单图排版:使用巨型字母分隔整张图片 [PowerPoint精美幻灯片实战教程]
- 全球与中国湿式剃须刀市场深度研究分析报告
- c语言解引用运算符,C++ 解引用(*)和箭头(-)运算符的重载