首页 | 邮件资讯 | 技术教程 | 解决方案 | 产品评测 | 邮件人才 | 邮件博客 | 邮件系统论坛 | 软件下载 | 邮件周刊 | 热点专题 | 工具
网络技术 | 操作系统 | 邮件系统 | 客户端 | 电子邮箱 | 反垃圾邮件 | 邮件安全 | 邮件营销 | 移动电邮 | 邮件软件下载 | 电子书下载

邮件服务器

技术前沿 | Qmail | IMail | MDaemon | Exchange | Domino | 其它 | Foxmail | James | Kerio | JavaMail | WinMail | Sendmail | Postfix | Winwebmail | Merak | CMailServer | 邮件与开发 | 金笛 |
首页 > 邮件服务器 > 邮件与程序开发 > 用C#访问Hotmail > 正文

用C#访问Hotmail

出处:仙人掌工作室 作者:仙人掌工作室 时间:2005-9-13 8:52:00
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等协议一样简单。 (下载本文的完整代码: HotmailCSharp_code.zip(8K)。 )
相关文章 热门文章
  • 微软推出新功能 提高Hotmail密码安全性
  • Hotmail新功能:“我的朋友可能被黑了”
  • 岁月催人老 微软Hotmail已经15岁了
  • 微软Hotmail邮件系统引入社交网站
  • 用hotmail空间组建自己的邮件系统
  • Hotmail升级版面向所有用户开放
  • 新版Hotmail支持Exchange ActiveSync协议
  • Hotmail发展历程回顾
  • 弱密码让Hotmail频遭钓鱼攻击
  • 微软讲述Hotmail背后的故事
  • 微软Hotmail停止支持WebDAV协议
  • 微软突然取消Hotmail附加照片功能激起众怒
  • 用C++ Builder实现电子邮件群发
  • 用Cdonts实现发送Email
  • Jmail的主要参数列表
  • ASP.NET 2.0发送电子邮件全面剖析之二
  • VC++ SMTP协议电子邮件传送剖析
  • 通过sina的smtp验证的Java发送邮件源代码
  • ASP.NET 2.0中发送电子邮件剖析之一
  • 在Asp.Net中使用SmtpMail发送邮件的方法
  • .NET环境下Email的技术介绍
  • ASP.NET 2.0发送电子邮件中存在的问题
  • 用ASP判断Email地址是否有效
  • IIS如何接收ServerXMLHTTP传过来的编码字符?
  • 自由广告区
     
    最新软件下载
  • SharePoint Server 2010 部署文档
  • Exchange 2010 RTM升级至SP1 教程
  • Exchange 2010 OWA下RBAC实现的组功能...
  • Lync Server 2010 Standard Edition 标..
  • Lync Server 2010 Enterprise Edition...
  • Forefront Endpoint Protection 2010 ...
  • Lync Server 2010 Edge 服务器部署文档
  • 《Exchange 2003专家指南》
  • Mastering Hyper-V Deployment
  • Windows Server 2008 R2 Hyper-V
  • Microsoft Lync Server 2010 Unleashed
  • Windows Server 2008 R2 Unleashed
  • 今日邮件技术文章
  • 腾讯,在创新中演绎互联网“进化论”
  • 华科人 张小龙 (中国第二代程序员 QQ...
  • 微软推出新功能 提高Hotmail密码安全性
  • 快压技巧分享:秒传邮件超大附件
  • 不容忽视的邮件营销数据分析过程中的算..
  • 国内手机邮箱的现状与未来发展——访尚..
  • 易观数据:2011Q2中国手机邮箱市场收入..
  • 穿越时空的爱恋 QQ邮箱音视频及贺卡邮件
  • Hotmail新功能:“我的朋友可能被黑了”
  • 入侵邻居网络发骚扰邮件 美国男子被重..
  • 网易邮箱莫子睿:《非你莫属》招聘多过..
  • 中国电信推广189邮箱绿色账单
  • 最新专题
  • 鸟哥的Linux私房菜之Mail服务器
  • Exchange Server 2010技术专题
  • Windows 7 技术专题
  • Sendmail 邮件系统配置
  • 组建Exchange 2003邮件系统
  • Windows Server 2008 专题
  • ORF 反垃圾邮件系统
  • Exchange Server 2007 专题
  • ISA Server 2006 教程专题
  • Windows Vista 技术专题
  • “黑莓”(BlackBerry)专题
  • Apache James 专题
  • 分类导航
    邮件新闻资讯:
    IT业界 | 邮件服务器 | 邮件趣闻 | 移动电邮
    电子邮箱 | 反垃圾邮件|邮件客户端|网络安全
    行业数据 | 邮件人物 | 网站公告 | 行业法规
    网络技术:
    邮件原理 | 网络协议 | 网络管理 | 传输介质
    线路接入 | 路由接口 | 邮件存储 | 华为3Com
    CISCO技术 | 网络与服务器硬件
    操作系统:
    Windows 9X | Linux&Uinx | Windows NT
    Windows Vista | FreeBSD | 其它操作系统
    邮件服务器:
    程序与开发 | Exchange | Qmail | Postfix
    Sendmail | MDaemon | Domino | Foxmail
    KerioMail | JavaMail | Winwebmail |James
    Merak&VisNetic | CMailServer | WinMail
    金笛邮件系统 | 其它 |
    反垃圾邮件:
    综述| 客户端反垃圾邮件|服务器端反垃圾邮件
    邮件客户端软件:
    Outlook | Foxmail | DreamMail| KooMail
    The bat | 雷鸟 | Eudora |Becky! |Pegasus
    IncrediMail |其它
    电子邮箱: 个人邮箱 | 企业邮箱 |Gmail
    移动电子邮件:服务器 | 客户端 | 技术前沿
    邮件网络安全:
    软件漏洞 | 安全知识 | 病毒公告 |防火墙
    攻防技术 | 病毒查杀| ISA | 数字签名
    邮件营销:
    Email营销 | 网络营销 | 营销技巧 |营销案例
    邮件人才:招聘 | 职场 | 培训 | 指南 | 职场
    解决方案:
    邮件系统|反垃圾邮件 |安全 |移动电邮 |招标
    产品评测:
    邮件系统 |反垃圾邮件 |邮箱 |安全 |客户端
    广告联系 | 合作联系 | 关于我们 | 联系我们 | 繁體中文
    版权所有:邮件技术资讯网©2003-2010 www.5dmail.net, All Rights Reserved
    www.5Dmail.net Web Team   粤ICP备05009143号