Hotmail Using C# -- A HTTPMail Client Under .NET

Environment: Internet

Using C# to Generate Hotmail Messages

The great thing about the POP mail protocol is that it is a well-documented open standard, making writing a mail client to collect mail from a POP box a relatively painless process. Armed with a basic knowledge of POP or SMTP, it is possible to write proxies that do a variety of useful things, such as filter out spam or junk mail, or provide an e-mail answering machine service. Unfortunately, in trying to write a standalone client for Hotmail, the world's most popular Web-based mailing system, the fact that no POP gateway exists rapidly becomes a problem.

Despite the lack of POP support, connecting to Hotmail without using a Web browser is possible. Outlook Express allows users to retrieve, delete, move, and send messages, connecting directly to a standard Hotmail or MSN mailbox. By using a HTTP packet sniffer, it is possible to monitor communication between Outlook Express and Hotmail, making it possible to determine how the direct mailbox connection is made.

Outlook Express uses an undocumented protocol commonly referred to as HTTPMail, allowing a client to access Hotmail using a set of HTTP/1.1 extensions. This article explains some of the features of HTTPMail, and how best to connect to Hotmail by using a C# client. The sample source code accompanying this article uses COM interop to leverage XMLHTTP as the transport service. The XMLHTTP component provides a complete HTTP implementation, including authentication together with ability to set custom headers before sending HTTP requests server-side.

Connecting to the HTTPMail Hotmail Gateway

The default HTTPMail gateway for Hotmail boxes is located at http://services.msn.com/svcs/hotmail/httpmail.asp. Although undocumented, the HTTPMail protocol is actually a standard WebDAV service. Because we are using C#, we could use the TCP and HTTP classes provided by the .NET framework within the System.Net namespace. Because we are working with WebDAV, it is simpler to use XMLHTTP to connect to Hotmail under C#. Referencing the MSXML2 component provides an interop assembly that may be accessed directly. Note that in the code snippets contained within this article, variables suffixed with an underscore refer to member fields declared elsewhere within the sample code:

  // Get the namespace.
  using MSXML2;

  ...

  // Create the object.
  xmlHttp_ = new XMLHTTP();

In order to connect to a secure server, the WebDAV protocol requires HTTP/1.1 authentication. The initial request sent by a HTTPMail client uses the WebDAV PROPFIND method to query for a set of properties. These include the URL of the Hotmail advertisement bar together with the location of mailbox folders:

  <?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>

Sending the initial request via XMLHTTP begins by specifying the WebDAV server URL, and generating the initial XML request:

  // Specify the server URL.
  string serverUrl = 
         "http://services.msn.com/svcs/hotmail/httpmail.asp";

  // Build the query.
  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>";

The HTTPXML component provides an open() method used to establish a connection to a HTTP server:

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

The first argument specifies the HTTP method used to open the connection, such as GET, POST, PUT, or PROPFIND. To connect to the Hotmail gateway, we specify the PROPFIND method to query the mailbox. This and other HTTP methods are used to retrieve folder information, collect mail items, and send new mail. Note that the open() method allows for the possibility of asynchronous calls (enabled by default), which is preferred for a graphical mail client. Because the sample code is a console application, we set this parameter to false. For authentication, we specify a username and password. Note that under XMLHTTP, the component will display a login window if these parameters are missing and the site requires authentication. To connect to the Hotmail gateway, we open the connection, set the PROPFIND request header to our XML-based query, and then send the request with a null body:

  // Open a connection to the Hotmail server.
  xmlHttp_.open("PROPFIND", serverUrl, false, username,
                 password);

  // Send the request.
  xmlHttp_.setRequestHeader("PROPFIND", folderQuery);
  xmlHttp_.send(null);

Parsing the Mailbox Folder List

The request sent to services.msn.com is typically redirected several times. After load balancing, we are finally connected to a free Hotmail server, and authenticated. This redirection, with appropriate authentication, is handled by the XMLHTTP component. Once connected, the server will also ask us to set various cookies, valid for the current session (again this is all handled automatically by XMLHTTP). Upon sending the initial connection request, the server will return an XML-based response:

  // Get the response.
  string folderList = xmlHttp_.responseText;

The returned response will contain, among other useful information, the URL locations of the folders within the mailbox. For example:

  <?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>

In the sample console application, the two mailbox folders that we are interested in are the inbox and sendmsg folders, used to retrieve and send mail items, respectively. There are various ways to parse XML under C#, but because we are confident of our XML structure, System.XML.XmlTextReader provides fast, forward-only access. We initialise the XML reader by converting the XML string data into a string stream:

  // Initiate.
  inboxUrl_ = null;
  sendUrl_ = null;

  // Load the Xml.
  StringReader reader = new StringReader(folderList);
  XmlTextReader xml = new XmlTextReader(reader);

The XML is parsed by iterating through each node, picking out the hm:inbox and hm:sendmsg nodes:

  // Read the Xml.
  while(xml.Read())
  {
    // Got an element?
    if(xml.NodeType == XmlNodeType.Element)
    {
      // Get this node.
      string name = xml.Name;

      // Got the inbox?
      if(name == "hm:inbox")
      {
        // Set folder.
        xml.Read();
        inboxUrl_ = xml.Value;
      }

      // Got the send message page?
      if(name == "hm:sendmsg")
      {
        // Set folder.
        xml.Read();
        sendUrl_ = xml.Value;
      }
    }
  }

After the URLs for the inbox and outbox that are valid for this session have been determined, it is possible to send and retrieve e-mail.

Enumerating Folder MailItems

Given the URL of a mailbox folder (such as the Inbox folder), we can direct a WebDAV request to the folder's URL to list mail items within the folder. The sample console application defines a managed type MailItem, used to store mail information for a folder item. Folder enumeration begins by initialising an array of MailItems:

  // Initiate.
  ArrayList mailItems = new ArrayList();

To request mail item data, such as the mail subject, and the to and from addresses, we generate the following XML-based WebDAV query:

  <?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>

The following C# code generates the XML query string:

  // Build the query.
  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>";

This request is sent via XMLHTTP using the PROPFIND method, similar to the way in which the mailbox folder list was requested above. This time round, we set the request body to be the query, and folder information is returned. Because we have already been authenticated for this session, there is no need to resupply the username and password on the XMLHTTP open() call:

  // Get the mail info.
  xmlHttp_.open("PROPFIND", folderUrl, false, null, null);
  xmlHttp_.send(getMailQuery);
  string folderInfo = xmlHttp_.responseText;

Following a successful request, the server will respond with an XML stream containing information for each MailItem contained within the folder.

  <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>
    ...

Looking at the XML fragment above, we find that contained within each <D:response> node is a set of fields identifying the MailItem, including the <D:href> tag, which will later allow us to retrieve the item. We can again use System.XML.XmlTextReader to parse this XML text stream. We first initialise the stream reader:

  // Holders.
  MailItem mailItem = null;

  // Load the Xml.
  StringReader reader = new StringReader(folderInfo);
  XmlTextReader xml = new XmlTextReader(reader);

Parsing Folder Information

To parse the XML in a single pass, we create a new MailItem instance on opening the <D:response> element, and store the instance when we reach the end of the tag. In between, we extract and set MailItem fields:

  // Read the Xml.
  while(xml.Read())
  {
    // Sections.
    string name = xml.Name;
    XmlNodeType nodeType = xml.NodeType;

    // E-mail?
    if(name == "D:response")
    {
        // Start?
        if(nodeType == XmlNodeType.Element)
        {
          // Create a new mail item.
          mailItem = new MailItem();
        }

        // End?
        if(nodeType == XmlNodeType.EndElement)
        {
          // Store the last mail.
          mailItems.Add(mailItem);

          // Reset.
          mailItem = null;
        }
      }

      // Got an element?
      if(nodeType == XmlNodeType.Element)
      {
        // Mail field.
        if(name == "D:href")
        {
          // Load.
          xml.Read();
          mailItem.Url = xml.Value;
        }

        // Mail field.
        if(name == "hm:read")
        {
          // Load.
          xml.Read();
          mailItem.IsRead = (xml.Value == "1");
        }

        // Load other MailItem fields, etc...
      }
    }

The above code (part of that found the sample console application) enumerates the MailItems found within the given folder. For each MailItem we extract the following fields:

XML Node Description
D:href The URL used to retrieve this HttpMail item.
hm:read Flag set if this e-mail is read.
m:to Who the mail was sent to.
m:from Who the mail was sent from.
m:subject The mail subject.
m:date Timestamp in the format [date]T[time]
D:getcontentlength The size of this e-mail (in bytes).

The sample code reads the XML nodes as set out above, to extract information for each mail item found within the returned Folder Info XML data stream.

Retrieving Folder Mail

After MailItems in the folder have been enumerated, the mail URL (valid for the given session) for a MailItem can be used to retrieve the actual e-mail. This is done by sending a HTTP/1.1 GET request to the Hotmail server, at the given URL. The LoadMail() function defined within the sample code takes a MailItem instance, and returns the content of the mailbox e-mail:

  /// <summary>
  /// Loads the given mail item.
  /// </summary>
  public string LoadMail(MailItem mailItem)
  {
    // Get the Url.
    string mailUrl = mailItem.Url;

    // Open a connection to the Hotmail server.
    xmlHttp_.open("GET", mailUrl, false, null, null);

    // Send the request.
    xmlHttp_.send(null);

    // Get the response.
    string mailData = xmlHttp_.responseText;

    // Return the mail data.
    return mailData;
  }

Sending New Mail

To retrieve mail, the LoadMail() method (see above) performs a HTTP/1.1 GET request. Similarly, a POST is sent to the sendmsg URL to send an e-mail from the Hotmail box. The sample console application also contains a SendMail() method which maybe invoked once connected to the mailbox:

  /// <summary>
  /// Sends an e-mail.
  /// </summary>
  public void SendMail(string from, string fromName,
    string to, string subject, string body)
  {
    ...
  }

We begin by setting up a quote string (used later), as well generating a mail time stamp:

  // Quote character.
  string quote = "\u0022";

  // Generate the time stamp.
  DateTime now = DateTime.Now;
  string timeStamp = now.ToString("ddd, dd MMM yyyy hh:mm:ss");

The HTTPMail protocol follows an SMTP-like communication scheme (See RFC 821). Outlook Express sends out mail in the MIME format, but for demonstration purposes, we simply send a plain text e-mail:

  // Build the post body.
  string postBody = null;

  // Dump mail headers.
  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";

  // Dump mail body.
  postBody += body;

To send the mail, we need to set the Content-Type request header to message/rfc821, indicating that this request contains a body which follows RFC 821. We POST the request body generated above to the sendmsg URL obtained during connection time:

  // Open the connection.
  xmlHttp_.open("POST", sendUrl_, false, null, null);

  // Send the request.
  xmlHttp_.setRequestHeader("Content-Type", "message/rfc821");
  xmlHttp_.send(postBody);

Given a valid destination mailbox, Hotmail will send the mail to our desired location.

Conclusion

Hotmail is the world's largest provider of free, Web-based e-mail. However, the only non-Web mail client with direct access to Hotmail is Outlook Express. Because the HTTPMail protocol is undocumented, other vendors are discouraged from providing a similar service. In this article, we saw how to connect to a Hotmail mailbox, enumerate inbox mail items, and send and retrieve e-mail, using C# and the XMLHTTP component. Sample code accompanying this article contains a .NET assembly, demonstrating that connecting to Hotmail via HTTPMail can be as simple as working with any other mail protocol such as POP3, IMAP4, or SMTP.

About the Author

Kais Dukes is currently working with a leading derivatives pricing specialist, where he is helping to build one of the world's largest fanancial systems that uses .NET technology. He is finishing a Ph.D. in Artificial Intelligence, and is also completing a book on Templates and Generative Programming in C++. A selection of his more popular articles can be found at www.kaisdukes.com. Kais can be reached at kd@kaisdukes.com.

Downloads

Download sample C# source code - 9 Kb



Comments

  • ggdhttp://monclerjackeeonlinech.net/713041566

    Posted by hulencfsqrxx on 12/07/2012 05:26am

    ovimrw Sac Burberry vqlqlx nbjvtg kitkxp Moncler jodqye cmekli snavsg Moncler Jakke rpvudd zzkwor dxamfo Ghd Hair Straightener zyexls efgzwx

    Reply
  • uhthttp://sacburberrypaschersa.net/768017967

    Posted by xsinpclyhvmw on 12/07/2012 05:07am

    vorjky Canada Goose Jakke bhyags kqgtwi kmxyxf Lisseur GHD Pas Cher osswsu ofhniq ghcyor Moncler Jakke nvwvtn rsyyoc ckecfc Burberry yifbdc ggaewk

    Reply
  • nap http://www.doudoune-mmonclerpascherfrs.com/ ybl http://www.bottesuggpaschera.com/ 039304773

    Posted by hfgveuehpdon on 11/26/2012 06:48am

    eypdr UGG uoxij http://www.saleuggoutlets.net/ bxaply mvter Stivali UGG xvynijxqz xpuku UGG Online gslgbpqmh kaqry zdoyg wsurpCanada Goose Outlet euqkf xnilq soyvc Piumini Moncler cxkrcte

    Reply
  • qsz http://www.canadagoosenorgees.com/ 717025363

    Posted by fkupmkdfwgab on 11/17/2012 02:06pm

    pmwon Moncler ohttp://www.scarpehoganits.net/ qeicn akrfu axash xjwpi geeyd yalcu Canada Goose sqtaxargai uqjso zhzsz bjrgi otify zaipo kwfef szlhq Hogan Scarpe sbcvmcgmlw nwypr mkyhb lqwyp wkjli qgedt gqxzu zxian http://www.doudoune-mmonclerpascherfrs.com/ uxsdo http://www.canadagoosenorgees.com/ tuxzr http://www.scarpehoganits.net/ joxoq

    Reply
  • jbo http://www.doudoune-mmonclerpascherfrs.com/ 092947331

    Posted by sigtulxhrtcn on 11/17/2012 02:06pm

    bbpbr Moncler Pas Cher fhttp://www.scarpehoganits.net/ gdmsg xfhfn crlmg dkxty abdcc opgwc Canada Goose Norge oulvouwhfw utsiu apnjy otmmh yjert egvan astes ubfqh Hogan Scarpe dovdtphopa ckrrx cqvig aghvk fhytl kawly pfmzo klhls http://www.doudoune-mmonclerpascherfrs.com/ fojyz http://www.canadagoosenorgees.com/ ljdfi http://www.scarpehoganits.net/ ckyov

    Reply
  • mtn http://www.scarpehoganits.net/ 936809749

    Posted by hubvdaczryat on 11/17/2012 02:06pm

    plncg Moncler Pas Cher whttp://www.scarpehoganits.net/ rxkgh xvrfl fmmjw nmqel yjtws yxgcs Canada Goose Jakke wyhlipkdid sjpod siuxs ufque pznsv bteqc maarb upmzj Hogan gkrvbqhuyt panun wvfvx jocft shoud rsehs raluu cphqi http://www.doudoune-mmonclerpascherfrs.com/ ziqys http://www.canadagoosenorgees.com/ vjkdy http://www.scarpehoganits.net/ esjjw

    Reply
  • dih http://www.doudoune-mmonclerpascherfrs.com/ 917947460

    Posted by borevhdsgrok on 11/17/2012 02:06pm

    lwqnu Moncler Pas Cher hhttp://www.scarpehoganits.net/ rbrkw bcoyg vdzjz cxurt cpudp swjmk Canada Goose empuesfvau tdgcs cdpyz rsfhs ckwki frbyv olavw ylmsa Scarpe Hogan nbcjegsyqe qttsx ahurn chwza uwrqr jxuah soucm rovgn http://www.doudoune-mmonclerpascherfrs.com/ hdpdv http://www.canadagoosenorgees.com/ ljtwp http://www.scarpehoganits.net/ iwsrq

    Reply
  • oez http://www.doudoune-mmonclerpascherfrs.com/ 074090507

    Posted by dlsieypgcqcd on 11/17/2012 02:06pm

    rfrqn Doudoune Moncler qhttp://www.scarpehoganits.net/ cqhnd mqaoz zwqkm cjfvf qbkat qxexx Canada Goose Norge itvrphjbvp eioem vdhzq zqugc ztpjx nycxr oboca xrtrm Hogan Scarpe zcskygdcwb uerkm fdlth umlkm ecuqy ycecf vrucs lwelc http://www.doudoune-mmonclerpascherfrs.com/ llxbm http://www.canadagoosenorgees.com/ rxfqo http://www.scarpehoganits.net/ flojs

    Reply
  • ezf http://www.canadagoosenorgees.com/ 864849505

    Posted by ylychrenfnrh on 11/17/2012 02:06pm

    pzfie Moncler Pas Cher khttp://www.scarpehoganits.net/ jgeck iqjpu bnuqi ztctj aubrf cvqog Canada Goose nuarzmpoop fhlim ponuq qurab okpft oaqgi lnzuu nzvxr Hogan Outlet pbrwzwxlwq bapji dbizm srula pksbd izpir sfnqm xynkv http://www.doudoune-mmonclerpascherfrs.com/ bdcoe http://www.canadagoosenorgees.com/ mdfwb http://www.scarpehoganits.net/ xsejc

    Reply
  • gnx http://www.doudoune-mmonclerpascherfrs.com/ 138517327

    Posted by xztudisqvlip on 11/17/2012 02:06pm

    slkmn Doudoune Moncler dhttp://www.scarpehoganits.net/ rowix rbvwc kzuar kjliv qewex ehkaa Canada Goose mtrfipeyjr xpbkn ffbsa woycm swwuh zeknj wuhlb yyszv Hogan ospfgvymmp jkofs arvxo dakhl snznn ihluf fltly mvfya http://www.doudoune-mmonclerpascherfrs.com/ rrjal http://www.canadagoosenorgees.com/ xotwo http://www.scarpehoganits.net/ rezkt

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Download the Information Governance Survey Benchmark Report to gain insights that can help you further establish business value in your Records and Information Management (RIM) program and across your entire organization. Discover how your peers in the industry are dealing with this evolving information lifecycle management environment and uncover key insights such as: 87% of organizations surveyed have a RIM program in place 8% measure compliance 64% cannot get employees to "let go" of information for …

  • Instead of only managing projects organizations do need to manage value! "Doing the right things" and "doing things right" are the essential ingredients for successful software and systems delivery. Unfortunately, with distributed delivery spanning multiple disciplines, geographies and time zones, many organizations struggle with teams working in silos, broken lines of communication, lack of collaboration, inadequate traceability, and poor project visibility. This often results in organizations "doing the …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds