Accessing Hotmail using C#

HotmailProxy

The proxy will be responsible for making HTTP requests to the Hotmail servers. This will require various things to be implemented:

  • Make requests using the PROPFIND method, instead of the usual GET and POST.
  • Handle redirection.
  • Handle cookies.
  • Handle HTTP authentication.
  • Send XML data to the remote host, which is basically the same as sending a string.

To send the requests and receive the responses the class will make use of the HttpWebRequest and HttpWebResponse classes. Cookies will be stored in a CookieContainer . And most importantly authentication can be done by adding a NetworkCredential object to the HttpWebRequest. This will fully implement HTTP authentication, how easy is that!

All classes reside in the System.Net namespace and are part of the .NET Framework, this means; easy use and documented code!

Let's start with building the class framework.

public class HotmailProxy
{
    private CookieContainer ccContainer;
    public HotmailProxy ()
    {
        ccContainer = new CookieContainer();
    }
}

Ok, not too interesting. Now let's get on with building the really important part, building the method that actually sends the client's request to a remote host. It will implement all the proxy's requirements that are stated above! The method will need to accommodate the request as a byte array, the destination, and the necessary credentials for authentication(which can be null if cookies are set after logging in):

private string SendRequestTo( byte [] requestBytes, Uri destination,
    NetworkCredential credential)

The first thing that needs to be done is build the HttpWebRequest object. The object will need to have a specific UserAgent header, otherwise Hotmail will decline the request (pfff, how conceited). Also it will have a few other headers initialized.

Implementation of the authentication process is done by adding the NetworkCredential object to the request, that object was quite difficult to build, read about it further on.

HttpWebRequest webRequest =
    (HttpWebRequest)WebRequest.Create(destination);
webRequest.Method = "PROPFIND";
webRequest.Accept = "*/*";
webRequest.AllowAutoRedirect = false;
webRequest.UserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; " +
    "Windows NT 5.0; .NET CLR 1.0.3705)";
webRequest.CookieContainer = new CookieContainer();
webRequest.ContentLength = requestBytes.Length;
webRequest.ContentType = "text/xml";
webRequest.Credentials = credential;
webRequest.CookieContainer.Add(ccContainer.GetCookies(destination));

Now the request has been build, we will write the request to the requested host and try to get a response:

    try
    {
        Stream reqStream = webRequest.GetRequestStream();
        reqStream.Write(requestBytes,0,requestBytes.Length);
        reqStream.Close();
        HttpWebResponse webResponse =
            (HttpWebResponse)webRequest.GetResponse();

After verification that a response was received, cookies and redirection can be handled. Otherwise an exception will be thrown (build your own MailException of some sort for this). Cookies should be compared to the stored cookies by matching names. Redirection is done by checking the HTTP status code, and recursively calling this method.

    if (webRequest.HaveResponse)
    {
        // First handle cookies
        foreach(Cookie retCookie in webResponse.Cookies)
        {
            bool cookieFound = false;
            foreach(Cookie oldCookie in
                ccContainer.GetCookies(destination))
            {
                if (retCookie.Name.Equals(oldCookie.Name))
                {
                    oldCookie.Value = retCookie.Value;
                    cookieFound = true;
                }
            }
            if (!cookieFound)
                ccContainer.Add(retCookie);
        }               
        // Next is redirection
        if ((webResponse.StatusCode == HttpStatusCode.Found) ||
            (webResponse.StatusCode == HttpStatusCode.Redirect) ||
            (webResponse.StatusCode == HttpStatusCode.Moved) ||
            (webResponse.StatusCode == HttpStatusCode.MovedPerm..y))
        {
            // Get new location and call recursively
            WebHeaderCollection headers = webResponse.Headers;
            return SendRequestTo(requestBytes,
                new Uri(headers["location"]),credential);   
        }

Now that redirection has been handled and all cookies are set, the response stream can be read to receive the final server's response. This finishes the method.

            // Read response
            StreamReader stream = new StreamReader
                (webResponse.GetResponseStream());
            string responseString = stream.ReadToEnd();
            stream.Close();
            return responseString;
        }
        throw new Exception("No response received from host.");
    }
    catch(WebException e)
    {
        throw new Exception("Exception occured while " +
            "sending request.",e);
    }
}

To complete the class a public interface will need to be provided, that calls the SendRequestTo method. The request is an XML string, so the method will need to translate that string into a byte array. The following code is pretty basic. Check the input, build the byte array and send away!

    public string SendRequest(string request,
        Uri destination,
        NetworkCredential credential)
    {
        if(request == null || request.Trim().Length == 0)
            throw new ArgumentNullException("request");
        else if (destination == null)
            throw new ArgumentNullException("destination");
        else
        {
            byte[] xmlBytes = Encoding.ASCII.GetBytes(request);
            return SendRequestTo(xmlBytes,destination, credential);
        }
    }

Because authentication isn't done in all the requests, the following method has been made available to make further requests from a selected host after logging in.

    public string SendRequest(string request, Uri destination)
    {
        return SendRequest(request,destination,null);
    }

Hora! This completes our proxy, it is now able to do all the things we started out to do! It is able to send requests to Hotmail servers across the world.

You might also like...

Comments

Contribute

Why not write for us? Or you could submit an event or a user group in your area. Alternatively just tell us what you think!

Our tools

We've got automatic conversion tools to convert C# to VB.NET, VB.NET to C#. Also you can compress javascript and compress css and generate sql connection strings.

“Computer Science is no more about computers than astronomy is about telescopes.” - E. W. Dijkstra