Home arrow C# arrow Page 4 - Hotmail Exposed: Access Hotmail using C#
C#

Hotmail Exposed: Access Hotmail using C#


Wouter runs us through the process of building our very own Hotmail client, allowing us to communicate with the Hotmail gateway using C#.

Author Info:
By: Wouter van Vugt
Rating: 5 stars5 stars5 stars5 stars5 stars / 111
October 23, 2003
TABLE OF CONTENTS:
  1. · Hotmail Exposed: Access Hotmail using C#
  2. · Building the Client
  3. · HotmailProxy
  4. · HotmailClient
  5. · Conclusion

print this article
SEARCH DEVARTICLES

Hotmail Exposed: Access Hotmail using C# - HotmailClient
(Page 4 of 5 )

Now for implementing a class that provides access to Hotmail. The following example will show how to connect to Hotmail using the proxy, get the msgfolderroot and request some information about mailboxes. The msgfolderroot can be queried for information such as mailbox names, message count and unread count. This will allow clients to determine how many messages are new, without having to download all the messages (this would be a stupid method to implement such behavior).

Using this example and the webpage provided at the top of this document, it will be easy to implement the rest of the email client (it was for me!).

First letís begin again with the class framework:

 public class HotmailClient
 {
  private HotmailProxy hHttp = null;
  
  public HotmailClient()
  {

}
Connect()

Now for the only public method, Connect(). This method will connect to Hotmail using HTTP authentication, it will parse the response to obtain the Url of the msgfolderroot. Next this Url will be used to determine some mailbox information.

First of all the proxy class and credentials needed for authentication are built:

 public void Connect(string username, string password)
 {
  hHttp = new HotmailHttp();
 NetworkCredential credentials =
new NetworkCredential(username,password,null);

Phew, that was hard, one complete line of code. :)  Easy enough as you can see! The next job will be to build the XML query for the msgfolderroot. (XmlHttp will return all kinds of nonsense about the inbox, advertisements and others, while as you can see only the msgfolderroot is requested).

  string query = "<?xml version='1.0'?>" +
  "<D:propfind xmlns:D='DAV:' " +
  "xmlns:h='http://schemas.microsoft.com/hotmail/' " +
  "xmlns:hm='urn:schemas:httpmail:'>" +
  "<D:prop>"    +
    hm:msgfolderroot/>" +
  "</D:prop>"    +
  "</D:propfind>";

 
The query and the credentials can be used to get a response from the Hotmail gateway located at http://services.msn.com/svcs/hotmail/httpmail.asp. This will cause several redirections and cause the HTTP authentication to take place. All can be done with just a single line of code.

  try
  {
  string hotmailEntryPoint =
"
http://services.msn.com/svcs/hotmail/httpmail.asp
string response = hHttp.SendRequest(query,
new Uri(hotmailEntryPoint),credentials);
   // Verify response
   if (response == null || response.Trim().Length == 0)
    throw new Exception();

The Hotmail server will respond with the Url of the msgfolderroot. This Url is placed in the XML based response, so it can be found using Xpath. Another method has been built to do just that.

   // Parse the response, further verifying it.
   Uri folderRootUri = ParseConnectResponse(response);

With the now obtained Url, information about all the mailboxes on the server can be retrieved.

   // Obtain available folders using folderRootUrl
   RetrieveMailboxes(folderRootUri);
  }
 catch(Exception e)
  {
   // Something went wrong.
  throw new MailException("Exception occured while
connecting to remote host.",e);
  }

This completes our first method. As you can see it calls two other methods, which we will now construct.  These two contain the interesting parts: parsing the response! But first an important helper method needs to be built; without it all XPath queries fail.

CreateNamespaceManager (XmlNameTable table)

To obtain the Url of the folder root we will use XPath. The problem lies in the fact that XPath will not return results for nodes that are declared in a namespace. It is able to do so, but information about namespaces needs to be stated with the XPath query. This can be done by constructing an XmlNamespaceManager that knows about the namespaces in the Hotmail responses. As these namespaces appear to be really constant, a special method can be built to construct the necessary object.

 private XmlNamespaceManager CreateNamespaceManager(
XmlNameTable table)
 {
  XmlNamespaceManager m = new XmlNamespaceManager(table);
  m.AddNamespace("hm","urn:schemas:httpmail:");
  m.AddNamespace("D","DAV:");
  m.AddNamespace("m","urn:schemas:mailheader:");
  m.AddNamespace("c","urn:schemas:contacts:");
  m.AddNamespace("h","
http://schemas.microsoft.com/hotmail/");
  return m;

 
ParseConnectResponse(string response)

To parse the response there are a two things that need to be done: place the returned response in an XmlDocument, and parse the document using XPath to obtain the Url of the msgfolderroot.

 private Uri ParseConnectResponse(string response)
 {
  try
  {
   // Load response into XmlDocument
   XmlDocument dom = new XmlDocument();
   dom.LoadXml(response);
   // Query XmlDocument for msgfolderroot node.
   string xpath = "//hm:msgfolderroot";
   XmlNamespaceManager context =
CreateNamespaceManager(dom.NameTable);
   XmlNode folderRoot = dom.SelectSingleNode(xpath,context);
   // Verify node
   if (folderRoot == null)
    throw new Exception("Node '" + xpath +
"' not found.");
   // Get node text and verify,
   string folderRootUrl = folderRoot.InnerText;
   if ((folderRootUrl == null) ||
(folderRootUrl.Trim().Length == 0))
    throw new MailException("No url found in node '" +
xpath + "'.");
   try
   {
    // Return the uri, this may result in a
// UriFormatException
    return new Uri(folderRootUrl);
   }
   catch
   {
    throw new MailException("Url found in node '" +
xpath + "' is invalid:" + folderRootUrl);
   }
  }
  catch(Exception e)
  {
   // Something went wrong.
   throw new MailException("Error occured while parsing " +
"connect response.",e);
  }
 }

The way this method works is pretty basic now. The correct query to make can be determined using the webpage stated in the introduction.  Itís also possible to use a network analyzer for this purpose. You will probably need to use both. To parse the response, the XmlNamespaceManager is built, and XPath is used. 

RetrieveMailboxes(Uri folderRootUrl)

The last method in this example will retrieve information about all mailboxes on the server. Basically it does the same thing as the first two methods combined, so you should already be able to build it yourself. The method is shown here for completion sake. It will build a query and send it to the Url of the now determined msgfolderroot.

 private void RetrieveMailboxes(Uri folderRootUrl)
 {
  try
  {
   // Build the needed query
   string query = "<?xml version='1.0'?>" +
   "<D:propfind xmlns:D='DAV:' " +
xmlns:hm='urn:schemas:httpmail:'>" +
     "<D:prop>"    +
     "<D:displayname/>" +
     "<hm:special/>"  +
     "<hm:unreadcount/>" +
     "<D:visiblecount/>" +
    "</D:prop>"    +
    "</D:propfind>";
   // Get a response from server No Credentials are used!
   string response = hHttp.SendRequest(query,folderRootUrl);
   // Verify response
   if (response == null || response.Trim().Length == 0)
    throw new ApplicationException
("No response received from host."); 
   // Load response into XmlDocument
   XmlDocument dom = new XmlDocument();
   dom.LoadXml(response);
   // Query XmlDocument for all mailboxes using XPath
   string xpath = "//D:response";
   XmlNamespaceManager context =
CreateNamespaceManager(dom.NameTable);
   XmlNodeList mailBoxNodes =
dom.SelectNodes(xpath,context);
   // Parse each node found
   foreach(XmlNode mailBoxNode in mailBoxNodes)
   {  
    try
    {
// Direct mapping using XPath, should not
// result in any errors
     // as long as Hotmail keeps it protocol
// the same.
     string type = mailBoxNode.SelectSingleNode(
 "descendant::hm:special",context).InnerText;
string nameUrl = mailBoxNode.SelectSingleNode(
 "descendant::D:href",context).InnerText;
     int visibleCount = Int32.Parse(mailBoxNode.
 SelectSingleNode("descendant::D
                              :visiblecount",context).InnerText);
     int unreadCount = Int32.Parse(mailBoxNode.
 SelectSingleNode("descendant::hm
 :unreadcount",context).InnerText);

     Console.WriteLine("MailBox found: " +
type + "\r\n" + "\turl: " +
nameUrl + "\r\n" + "\tVisible: " +
visibleCount + "\r\n" + "\tUnread: " +
unreadCount + "\r\n");

     }
     catch(Exception e)
     {
      Console.WriteLine("Exception occured
while obtaining mailbox info: " + e.Message);
     }
    }
   }
   catch(Exception e)
   {
    // Something went wrong.
throw new ApplicationException("Error occured while retrieving available mailboxes.",e);
   }
  }


blog comments powered by Disqus
C# ARTICLES

- Introduction to Objects and Classes in C#, P...
- Visual C#.NET, Part 1: Introduction to Progr...
- C# - An Introduction
- Hotmail Exposed: Access Hotmail using C#
- Razor Sharp C#
- Introduction to Objects and Classes in C#
- Making Your Code CLS Compliant
- Programming with MySQL and .NET Technologies
- Socket Programming in C# - Part II
- Socket Programming in C# - Part I
- Creational Patterns in C#
- Type Conversions
- Creating Custom Delegates and Events in C#
- Inheritance and Polymorphism
- Understanding Properties in C#

Watch our Tech Videos 
Dev Articles Forums 
 RSS  Articles
 RSS  Forums
 RSS  All Feeds
Write For Us 
Weekly Newsletter
 
Developer Updates  
Free Website Content 
Contact Us 
Site Map 
Privacy Policy 
Support 

Developer Shed Affiliates

 




© 2003-2017 by Developer Shed. All rights reserved. DS Cluster - Follow our Sitemap
Popular Web Development Topics
All Web Development Tutorials