<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">
<channel>
<title>Stardeveloper</title>
<link>http://www.stardeveloper.com/</link>
<description>Learn web application development.</description>
<language>en-us</language>
<ttl>60</ttl>
<pubDate>Thu, 02 Sep 2010 16:06:09 GMT</pubDate><generator><![CDATA[http://www.stardeveloper.com/articles/display.html?article=2008112101&page=1]]></generator><copyright>Copyright 1999 - 2010 Stardeveloper.com, All Rights Reserved.</copyright>
<lastBuildDate>Thu, 02 Sep 2010 11:28:00 GMT</lastBuildDate>
<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.stardeveloper.com/StardevelopercomArticleHeadlines" /><feedburner:info uri="stardevelopercomarticleheadlines" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
<title>Real-World example of load time improvement using HTTP static resource caching</title>
<link>http://feeds.stardeveloper.com/~r/StardevelopercomArticleHeadlines/~3/Yzd1D7rJh-0/</link>
<description>&lt;p&gt;If you read the article about &lt;a href="http://www.stardeveloper.com/articles/expires-and-max-age-headers-in-aspnet/"&gt;using &lt;code&gt;Expires&lt;/code&gt; and &lt;code&gt;Max-Age&lt;/code&gt; headers to improve website load times&lt;/a&gt;, then you must be wondering what if any improvement this may have in the real-World. In this article, I am going to provide you with statistics of the load time of a sample page on Stardeveloper.com, and how using the &lt;a href="http://www.stardeveloper.com/articles/expires-and-max-age-headers-in-aspnet/"&gt;HTTP static resource caching technique&lt;/a&gt;, discussed in that article, resulted in load time improvement by an order of magnitude. So keep on reading!&lt;/p&gt;

&lt;h2&gt;Tools required to measure the load time of any web page&lt;/h2&gt;

&lt;p&gt;The first thing I want to share is the tool I use to measure the load time of a web page. The tool is named &lt;a href="http://www.fiddler2.com/"&gt;Fiddler&lt;/a&gt; and it works on Windows. It is obviously free to use. I use browsers like Safari, Firefox and Google's Chrome, and Fiddler works with all of them. To get started, download and install Fiddler from the link on their website. Then open any browser and start browsing the internet the way you normally do. Then when you switch the window back to Fiddler, you will see the details of the parent request and the child requests attached with every request you send using the browser. You can view details of a single page, like its request and response headers, load time, bytes sent and received, etc. or select a parent page, right-click, and select the child requests attached to that request, and then you can view the timeline for all the child requests. It is a very useful program and you will love it the moment you start using it.&lt;/p&gt;

&lt;h2&gt;Load time improvements&lt;/h2&gt;

&lt;p&gt;The sample page whose load time I am going to share in this article is actually the article itself about &lt;a href="http://www.stardeveloper.com/articles/expires-and-max-age-headers-in-aspnet/"&gt;using &lt;code&gt;Expires&lt;/code&gt; and &lt;code&gt;Max-Age&lt;/code&gt; headers to turn on static resource caching in ASP.NET&lt;/a&gt;. I am going to first share with you the load time and bytes sent/received when that page was accessed the &lt;i&gt;first time&lt;/i&gt; after clearing the browser's cache. The IIS server that Stardeveloper.com runs on will send a &lt;code&gt;Max-Age&lt;/code&gt; header for every static resource requested for that page with an expiry date set to one year in the future. This makes sure that the browser will cache the static resources like CSS, JavaScript and images on its hard disk. Then I will share you the stats when the same page was accessed the &lt;i&gt;second time&lt;/i&gt;. And you will see how much improvement in load time it resulted in and how wonderful a small change like enabling static resource caching using web.config file really is in ASP.NET.&lt;/p&gt;

&lt;h3&gt;Load time of the sample page the first time it was requested&lt;/h3&gt;

&lt;p&gt;The first time I requested the sample page, the HTTP request resulted in 20 child requests once that page began to load, obviously to load all the CSS, JavaScript and image files. It took a total of 12.8 seconds. Total bytes received were ~217 KB.&lt;/p&gt;

&lt;a href="http://www.stardeveloper.com/images/http-request-stats-first-request-uncached.png"&gt;&lt;img src="http://www.stardeveloper.com/images/http-request-stats-first-request-uncached-thumbnail.png" width="300" height="200" border="0" alt="Load time of the web page the first time it was requested from a browser with cache cleared" /&gt;&lt;/a&gt;

&lt;a href="http://www.stardeveloper.com/images/http-timeline-first-request-uncached.png"&gt;&lt;img src="http://www.stardeveloper.com/images/http-timeline-first-request-uncached-thumbnail.png" width="300" height="200" border="0" alt="Timeline of the web page the first time it was requested from a browser with cache cleared" /&gt;&lt;/a&gt;

&lt;h3&gt;Load time of the sample page the second time it was requested&lt;/h3&gt;

&lt;p&gt;The second time when I requested the same page, the HTTP request resulted in only 7 child requests (13 less than the first time). The time it took to load the full page was only just a little over 5 seconds (approx. 7 seconds less than the first time). Total bytes received were also less by a good order of magnitude, they were only about 45 KB (compared to 217 KB the first time).&lt;/p&gt;

&lt;a href="http://www.stardeveloper.com/images/http-request-stats-second-request-cached.png"&gt;&lt;img src="http://www.stardeveloper.com/images/http-request-stats-second-request-cached-thumbnail.png" width="300" height="200" border="0" alt="Load time of the web page the second time it was requested from the browser" /&gt;&lt;/a&gt;

&lt;a href="http://www.stardeveloper.com/images/http-timeline-second-request-cached.png"&gt;&lt;img src="http://www.stardeveloper.com/images/http-timeline-second-request-cached-thumbnail.png" width="300" height="200" border="0" alt="Timeline of the web page the second time it was requested from the browser" /&gt;&lt;/a&gt;

&lt;h2&gt;What if you had not enabled static resource caching in IIS?&lt;/h2&gt;

&lt;p&gt;In that case when the page was requested a second time, the browser would have sent &lt;code&gt;If-Modified-Since&lt;/code&gt; request for &lt;i&gt;every&lt;/i&gt; static resource (CSS, JavaScript and images) it encounterd on the web page. This would have inflated the request count from 7 to 20. The server in return would have sent a 304 'Document not modified' header back saying that the documents have not been modified sine they were requested the first time. While this may not have inflated the bytes received too much, but this overall process would have resulted in at least 13 extra round trips to and from the server which would have slowed the loading of the web page.&lt;/p&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;It will take just a few minutes to &lt;a href="http://www.stardeveloper.com/articles/expires-and-max-age-headers-in-aspnet/"&gt;setup static resource caching using &lt;code&gt;Expires&lt;/code&gt; or &lt;code&gt;Max-Age&lt;/code&gt; headers as described in the previous article using just the web.config file&lt;/a&gt; if you are using ASP.NET. If you weren't convinced when you read that article the first time, I hope this article will convince you enough to make the necessary changes. When you have made the changes, you can confirm the improvement in load time using Fiddler. Some times 20% of small changes can make 80% of the difference in load time and this technique is one of those 20% changes. Good luck!&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.stardeveloper.com/~ff/StardevelopercomArticleHeadlines?a=Yzd1D7rJh-0:x9RPcAk8XWA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/StardevelopercomArticleHeadlines?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.stardeveloper.com/~ff/StardevelopercomArticleHeadlines?a=Yzd1D7rJh-0:x9RPcAk8XWA:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/StardevelopercomArticleHeadlines?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/StardevelopercomArticleHeadlines/~4/Yzd1D7rJh-0" height="1" width="1"/&gt;</description>
<guid isPermaLink="false"><![CDATA[http://www.stardeveloper.com/articles/real-world-example-of-load-time-improvement-after-using-static-resource-caching/]]></guid>
<author>Faisal Khan</author>
<pubDate>Thu, 02 Sep 2010 11:28:00 GMT</pubDate>
<atom:link href="http://feeds.stardeveloper.com/StardevelopercomArticleHeadlines" rel="self" type="application/rss+xml" /><feedburner:origLink>http://www.stardeveloper.com/articles/real-world-example-of-load-time-improvement-after-using-static-resource-caching/</feedburner:origLink></item>
<item>
<title>Setting Expires and Max-Age Headers for static resources in ASP.NET</title>
<link>http://feeds.stardeveloper.com/~r/StardevelopercomArticleHeadlines/~3/BvCijScayBo/</link>
<description>&lt;p&gt;As developers, we are constantly striving to improve the performance of our web applications. While we can do everything on the server-side from improved database design and access code to caching using built-in ASP.NET &lt;code&gt;Cache&lt;/code&gt; object and &lt;code&gt;OutputCache&lt;/code&gt; directives in the user controls and ASP.NET pages, tests conducted show that it does not result in more than 5-12% improvement in the &lt;em&gt;load time&lt;/em&gt; of a web page. The majority of the time to load a web page is taken by static resources like CSS, JavaScript and image files. You can use browser add-ons like &lt;a href="http://code.google.com/speed/page-speed/"&gt;Page Speed&lt;/a&gt; and &lt;a href="http://developer.yahoo.com/yslow/"&gt;YSlow&lt;/a&gt; in Firefox browser, or a stand-alone application like &lt;a href="http://www.fiddler2.com/fiddler2/"&gt;Fiddler&lt;/a&gt;, to measure the load time of your website. In this article, we will focus on one simple yet very effective technique to speed up the load time of your website, and that is to use couple of handly HTTP headers to tell client browser or the intermediary proxy server to cache static resources from our web server. It will not take more than a few minutes for you to set them so please just focus a little on what is to follow as this will have good effect on the performance of your website.&lt;/p&gt;

&lt;h2&gt;What is Caching and why does it matter?&lt;/h2&gt;

&lt;p&gt;When a browser sends a request for a web page, that web page sends HTML markup back to the client browser. That HTML markup among the actual textual content, also contains markup to load accompanying CSS, JavaScript and image files. A very simple HTML page can make a browser go fetch, each time it is requested to load, all the heavy CSS, JavaScript and images stuff. Since the browser knows that many of these resources are static and may not have changed between different requests, the next time it is confronted with a request to load these resources, by the same or a different page on the same server, it checks with the server using &lt;code&gt;If-Modified-Since&lt;/code&gt; HTTP header to make sure to only load these resources if they have changed between requests. This is highly efficient stuff and is almost always going-on on your ASP.NET website whether you know it or not. So how can you improve it further?&lt;/p&gt;

&lt;h2&gt;Introduction to Expires and Max-Age headers&lt;/h2&gt;

&lt;p&gt;You can use &lt;code&gt;Expires&lt;/code&gt; or &lt;code&gt;Max-Age&lt;/code&gt; HTTP headers to tell the browser the first time it requests a static resource, like CSS, JavaScript or image file, to cache it for at least like 7 days, a month or an year. Most experts recommend sending an expiry date for your static content to an year in the future. According to &lt;a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html"&gt;w3.org&lt;/a&gt;, &lt;em&gt;an expiry date for static content must not be set to more than one year in the future&lt;/em&gt;. When you set an expiry date using &lt;code&gt;Expires&lt;/code&gt; or &lt;code&gt;Max-Age&lt;/code&gt; headers, the differences between the two we'll look in a moment, the browser will cache these resources on the client's hard disk and will not even send a &lt;code&gt;If-Modified-Since&lt;/code&gt; header to the server and will simply load the static files from the browser's local cache right away. This saves at least one extra round trip of request/response from and to the server for &lt;i&gt;every&lt;/i&gt; static resource. So if there are 12 CSS, JavaScript and image files, this saves 12 round trips. To the end-user, it appears as if the website is very fast and the document has loaded instantaneously. This speeds up the overall load time of the whole website, quite a bit.&lt;/p&gt;

&lt;h2&gt;How to make changes to static files whose expiry dates have been set to far in the future?&lt;/h2&gt;

&lt;p&gt;One thing to mention here is that although setting expiry date of the static resources to a far date in the future is very handy, you should keep in mind that if you want to change the static file on the server and want all the user's to load the newer and updated CSS, JavaScript or image file, then you should simply use a new name for that static file. For instance, if you had an image with the name of &lt;code&gt;logo.png&lt;/code&gt; in your website to display the logo of your website, and now you want to update or change it to a new one, then simply create a new file and save it as &lt;code&gt;logo-1.png&lt;/code&gt; and edit the HTML markup in your ASP.NET web application to refer to the new logo image file. Simple technique!&lt;/p&gt;

&lt;h2&gt;How to set Expires and Max-Age headers in ASP.NET?&lt;/h2&gt;

&lt;p&gt;The discussion so far about caching of static resources and HTTP headers applies equally to all web servers and is not specific to IIS. But what we will learn now is very specific to ASP.NET. We will now learn how to set &lt;code&gt;Expires&lt;/code&gt; and/or &lt;code&gt;Max-Age&lt;/code&gt; headers for static resources on our ASP.NET websites and web applications using no programming at all. We will simply add a few lines in web.config file of our ASP.NET web application and we'll be done.&lt;/p&gt;

&lt;h3&gt;Setting Max-Age header&lt;/h3&gt;

&lt;p&gt;To set a &lt;code&gt;Max-Age&lt;/code&gt; header for all static resources on your web server, add following lines in your ASP.NET web application's web.config file: &lt;/p&gt;

&lt;pre&gt;&amp;lt;/system.webServer&amp;gt;
	&amp;lt;staticContent&amp;gt;
		&amp;lt;clientCache cacheControlMode=&amp;quot;UseMaxAge&amp;quot; cacheControlMaxAge=&amp;quot;365.00:00:00&amp;quot;/&amp;gt;
	&amp;lt;/staticContent&amp;gt;
&amp;lt;/system.webServer&amp;gt;&lt;/pre&gt;

&lt;p&gt;The above markup tells the IIS to send &lt;code&gt;Max-Age&lt;/code&gt; HTTP header when any static resource (CSS, JavaScript, images, etc.) is requested from the server. To use &lt;code&gt;Max-Age&lt;/code&gt; header, you have to set the &lt;code&gt;cacheControlMode&lt;/code&gt; attribute to &lt;code&gt;&amp;quot;UseMaxAge&amp;quot;&lt;/code&gt;. The value of this header is a &lt;em&gt;relative&lt;/em&gt; timespan value set to a far date and time in the future. In the example markup given above, we have set the expiry date and time to 365 days in the future. Had you wanted to just set the expiry date to, let's say, 7 days, you would have set the &lt;code&gt;cacheControlMaxAge&lt;/code&gt; attribute to &amp;quot;7.00:00:00&amp;quot;. The format for this attribute is &lt;code&gt;d.hh.mm:ss&lt;/code&gt; where &lt;code&gt;d&lt;/code&gt; is day(s), &lt;code&gt;hh&lt;/code&gt; is hours, &lt;code&gt;mm&lt;/code&gt; is minutes and &lt;code&gt;ss&lt;/code&gt; is seconds.&lt;/p&gt;

&lt;h3&gt;Setting Expires header&lt;/h3&gt;

&lt;p&gt;To set an &lt;code&gt;Expires&lt;/code&gt; header for all static resources on your web server, add following lines in your ASP.NET web application's web.config file: &lt;/p&gt;

&lt;pre&gt;&amp;lt;/system.webServer&amp;gt;
	&amp;lt;staticContent&amp;gt;
		&amp;lt;clientCache cacheControlMode=&amp;quot;UseExpires&amp;quot; httpExpires=&amp;quot;Thu, 01 Sep 2011 12:00:00 UTC&amp;quot;/&amp;gt;
	&amp;lt;/staticContent&amp;gt;
&amp;lt;/system.webServer&amp;gt;&lt;/pre&gt;

&lt;p&gt;To use &lt;code&gt;Expires&lt;/code&gt; header, you have to set the &lt;code&gt;cacheControlMode&lt;/code&gt; attribute to &lt;code&gt;&amp;quot;UseExpires&amp;quot;&lt;/code&gt;. The value of the &lt;code&gt;Expires&lt;/code&gt; header is a fixed date and time in the future, unlike &lt;code&gt;Max-Age&lt;/code&gt; in which the value is a relative date and time (timespan) in the future. You also have to be cautious in correctly entering the date and time value for the &lt;code&gt;Expires&lt;/code&gt; header as given the in the sample above. Any mistake in the format, and your &lt;code&gt;Expires&lt;/code&gt; header will be rendered useless.&lt;/p&gt;

&lt;h2&gt;Which is better? Expires or Max-Age?&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Expires&lt;/code&gt; was specified in HTTP 1.0 specification as compared to &lt;code&gt;Max-Age&lt;/code&gt;, which was introduced in the early HTTP 1.1 specification. The value of the &lt;code&gt;Expires&lt;/code&gt; header has to be in a very specific date and time format, any error in which will make your resources non-cacheable. The &lt;code&gt;Max-Age&lt;/code&gt; header's value when sent to the browser is in seconds, the chances of any error happening in which is quite less.&lt;/p&gt;

&lt;p&gt;Since you can specify only one of the two headers in your web.config file, I'd suggest going with the &lt;code&gt;Max-Age&lt;/code&gt; header because of the flexibility it offers in setting a relative timespan from the present date to a date in the future. You can basically set and forget, as compared to the case with &lt;code&gt;Expires&lt;/code&gt; header, whose value you will have to remember to update at least once every year. And if you set both headers programmatically from within your code, know that the value of &lt;code&gt;Max-Age&lt;/code&gt; header will take precedence over &lt;code&gt;Expires&lt;/code&gt; header. So, something to keep in mind there as well.&lt;/p&gt;

&lt;p&gt;Now that you are up-to-speed in setting up HTTP cache headers for your static resources, on the next page, I will provide you real-World statistics of using this technique to improve load time of a web page. You will be surprised to see the results.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.stardeveloper.com/~ff/StardevelopercomArticleHeadlines?a=BvCijScayBo:jLGpdVpg6bQ:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/StardevelopercomArticleHeadlines?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.stardeveloper.com/~ff/StardevelopercomArticleHeadlines?a=BvCijScayBo:jLGpdVpg6bQ:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/StardevelopercomArticleHeadlines?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/StardevelopercomArticleHeadlines/~4/BvCijScayBo" height="1" width="1"/&gt;</description>
<guid isPermaLink="false"><![CDATA[http://www.stardeveloper.com/articles/expires-and-max-age-headers-in-aspnet/]]></guid>
<author>Faisal Khan</author>
<pubDate>Tue, 31 Aug 2010 12:41:00 GMT</pubDate>
<atom:link href="http://feeds.stardeveloper.com/StardevelopercomArticleHeadlines" rel="self" type="application/rss+xml" /><feedburner:origLink>http://www.stardeveloper.com/articles/expires-and-max-age-headers-in-aspnet/</feedburner:origLink></item>
<item>
<title>Setting up SPF Record for BlackBerry Internet Service</title>
<link>http://feeds.stardeveloper.com/~r/StardevelopercomArticleHeadlines/~3/NDRU6QtHzRM/</link>
<description>&lt;p&gt;It is imperative for a person who owns a domain name or runs a website to understand &lt;a href="http://www.stardeveloper.com/articles/what-is-sender-policy-framework/" title="What is Sender Policy Framework?" onclick="_gaq.push(['_trackEvent', 'internal-movement', '/articles/spf-record-for-blackberry-internet-service : /articles/what-is-spf', 'article']);"&gt;what is SPF&lt;/a&gt; (Sender Policy Framework) and how it works to provide control to the webmaster to explicitly specify which mail servers can send emails on the behalf of this domain name. Once, you have understood &lt;a href="http://www.stardeveloper.com/articles/what-is-sender-policy-framework/" title="What is Sender Policy Framework?" onclick="_gaq.push(['_trackEvent', 'internal-movement', '/articles/spf-record-for-blackberry-internet-service : /articles/what-is-spf', 'article']);"&gt;Sender Policy Framework&lt;/a&gt;, you should familiarize yourself with &lt;a href="http://www.stardeveloper.com/articles/spf-record-syntax/" title="SPF Record Syntax" onclick="_gaq.push(['_trackEvent', 'internal-movement', '/articles/spf-record-for-blackberry-internet-service : /articles/spf-record-syntax', 'article']);"&gt;SPF record syntax&lt;/a&gt;. Learning its syntax will allow you to setup an SPF record for your website.&lt;/p&gt;

&lt;p&gt;In this article, we will talk about a specific problem that many people who use popular &lt;a href="http://blog.stardeveloper.com/tagged/BlackBerry" title="Faisal Khan's blog posts about BlackBerry devices" onclick="_gaq.push(['_trackEvent', 'internal-movement', '/articles/spf-record-for-blackberry-internet-service : blog', 'article']);"&gt;BlackBerry devices&lt;/a&gt; may encounter when they have specified SPF records for their domain names. Every BlackBerry user uses either BIS (BlackBerry Internet Service) or BES (BlackBerry Enterprise Server) to setup one or more email addresses with his BlackBerry device. BES is beyond the scope of this article. For personal users who own domain names and have setup SPF records for their websites and have also setup their domains' email addresses with their BlackBerry devices, this article is for them.&lt;/p&gt;

&lt;h2&gt;Sending Emails with BlackBerry&lt;/h2&gt;

&lt;p&gt;When you setup your email address with BlackBerry Internet Service (BIS) and also have valid SPF records for your website's domain name, &lt;em&gt;problem arises when you send email from your BlackBerry device&lt;/em&gt;. That email will most probably end up being sent from BlackBerry's SMTP servers. And since you did not include BlackBerry's SMTP servers in your domain name's SPF records, it becomes uncertain if the email will make it to the destination mail box.&lt;/p&gt;

&lt;div class="note"&gt;This of course implies that every email that you send from your BlackBerry device is important to you. And since you are using BlackBerry, it is fair to assume that it is the case.&lt;/div&gt;

&lt;p&gt;So, what is the solution?&lt;/p&gt;

&lt;h2&gt;Including BlackBerry SMTP Servers in your domain's SPF Records&lt;/h2&gt;

&lt;p&gt;The solution is to enlist or include all BlackBerry SMTP servers in the SPF record of your domain name if they are not already there.&lt;/p&gt;

&lt;p&gt;This sounds fairly simple but it is not. We are not provided a comprehensive list of all SMTP servers that BlackBerry uses to send your emails. So what to do? The solution that I have come up after doing my bit of research online is to &lt;i&gt;include&lt;/i&gt; SMTP servers from North America (NA) and Europe (EU) used by BlackBerry. There are 2 domain names to include in your SPF records as given below:&lt;/p&gt;

&lt;h3&gt;BIS NA (North America) BlackBerry&lt;/h3&gt;

&lt;p&gt;For North American SMTP servers, use the following &lt;i&gt;include&lt;/i&gt; directive to include all SMTP servers:&lt;/p&gt;

&lt;pre&gt;include:srs.bis.na.blackberry.com&lt;/pre&gt;

&lt;h3&gt;BIS EU (Europe) BlackBerry&lt;/h3&gt;

&lt;p&gt;For European SMTP servers, use the following &lt;i&gt;include&lt;/i&gt; directive to include all SMTP servers:&lt;/p&gt;

&lt;pre&gt;include:srs.bis.eu.blackberry.com&lt;/pre&gt;

&lt;h3&gt;Final Sample SPF Record&lt;/h3&gt;

&lt;p&gt;Here is a sample SPF record for a domain that has included BlackBerry SMTP servers from both NA and EU:&lt;/p&gt;

&lt;pre&gt;"v=spf1 a include:srs.bis.na.blackberry.com include:srs.bis.eu.blackberry.com ~all"&lt;/pre&gt;

&lt;p&gt;If you find it hard to understand the SPF syntax given above, please follow the tutorial on &lt;a href="http://www.stardeveloper.com/articles/spf-record-syntax/" title="Learn SPF Record Syntax" onclick="_gaq.push(['_trackEvent', 'internal-movement', '/articles/spf-record-for-blackberry-internet-service : /articles/spf-record-syntax', 'article']);"&gt;SPF record syntax&lt;/a&gt; to learn more about it.&lt;/p&gt;

&lt;div class="note"&gt;I am not aware of any SMTP servers for BlackBerry out of North America and Europe. If you think you can improve the SPF record given above to more comprehensively include all BlackBerry SMTP servers, then feel free to &lt;a href="http://www.stardeveloper.com/contact.aspx" title="Contact Faisal Khan" onclick="_gaq.push(['_trackEvent', 'internal-movement', '/articles/spf-record-for-blackberry-internet-service : contact', 'article']);"&gt;share the information with me&lt;/a&gt;. I will keep this article updated with the latest information that I have on this topic.&lt;/div&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;In this article we learned how to setup SPF records to include BlackBerry SMTP servers from both North America and Europe so that the emails that are sent from our BlackBerry devices will be delivered to the destination mail box.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.stardeveloper.com/~ff/StardevelopercomArticleHeadlines?a=NDRU6QtHzRM:HH8vKFXg3Qs:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/StardevelopercomArticleHeadlines?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.stardeveloper.com/~ff/StardevelopercomArticleHeadlines?a=NDRU6QtHzRM:HH8vKFXg3Qs:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/StardevelopercomArticleHeadlines?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/StardevelopercomArticleHeadlines/~4/NDRU6QtHzRM" height="1" width="1"/&gt;</description>
<guid isPermaLink="false"><![CDATA[http://www.stardeveloper.com/articles/spf-record-for-blackberry-internet-service/]]></guid>
<author>Faisal Khan</author>
<pubDate>Tue, 27 Apr 2010 10:18:00 GMT</pubDate>
<atom:link href="http://feeds.stardeveloper.com/StardevelopercomArticleHeadlines" rel="self" type="application/rss+xml" /><feedburner:origLink>http://www.stardeveloper.com/articles/spf-record-for-blackberry-internet-service/</feedburner:origLink></item>
<item>
<title>SPF Record Syntax</title>
<link>http://feeds.stardeveloper.com/~r/StardevelopercomArticleHeadlines/~3/AWhpXjCDYCU/</link>
<description>&lt;p&gt;Sender Policy Framework prevents fraudulent abuse of your domain name in emails sent by others claiming to be sent from your domain name. This cuts down the spam which was originating from spammers who were using your domain name to bypass filters on other users' email addresses.&lt;/p&gt;

&lt;p&gt;A domain name which does not have an SPF record set in its DNS records is open to spammers to use the address of this domain name in the 'From' field of their emails. They can then send thousands of these unsolicited emails to end users. And by using the repute of that domain name, can entice users to click on links which lead to their products, and to  websites that fraudulently seek confidential and sensitive information (phishing attacks).&lt;/p&gt;

&lt;p&gt;It is thus very important that you understand &lt;a href="http://www.stardeveloper.com/articles/what-is-sender-policy-framework/" title="What is Sender Policy Framework?" onclick="_gaq.push(['_trackEvent', 'internal-movement', '/articles/spf-record-syntax : /articles/what-is-spf', 'article']);"&gt;what is Sender Policy Framework&lt;/a&gt; (SPF) and how it works.&lt;/p&gt;

&lt;p&gt;SPF works by making you explicitly declare a list of hosts and IP addresses from which legitimate emails can originate for your domain name. This is called creating a &lt;i&gt;white list&lt;/i&gt;. You can also create a &lt;i&gt;black list&lt;/i&gt; by explicitly declaring hosts and IP addresses which &lt;strong&gt;cannot&lt;/strong&gt; send emails for your domain name. Generally, only a white list is created. Any other host or IP address not present in the white list is set to fail or soft fail, as the case may be.&lt;/p&gt;

&lt;h2&gt;What should be included in an SPF record?&lt;/h2&gt;

&lt;p&gt;An SPF record should comprehensively list all the hosts and IP addresses from which your website or domain name sends emails. This generally means an &lt;code&gt;A&lt;/code&gt; record (IP address of your website), SMTP Servers, IP addresses from your company's network from which an email may originate, and any third party mailers, e.g., Google Apps, BlackBerry Internet Service, etc.&lt;/p&gt;

&lt;p&gt;When you have created such a list, you should use SPF record syntax to publish this list in the DNS records of your domain name.&lt;/p&gt;

&lt;h2&gt;Introduction to SPF record syntax&lt;/h2&gt;

&lt;p&gt;SPF record syntax follows standard DNS syntax to declare a &lt;i&gt;policy&lt;/i&gt; using a list of &lt;i&gt;mechanisms&lt;/i&gt;. &lt;em&gt;A mechanism is any &lt;i&gt;rule&lt;/i&gt; you specify as part of your SPF record to allow or disallow a host or IP address range&lt;/em&gt;. You can specify zero or more mechanisms, each delimited by white space. All of these mechanisms constitute a policy for your domain name. An SPF record always begins with &lt;code&gt;v=spf1&lt;/code&gt; and ends with &lt;code&gt;~all&lt;/code&gt;, as shown below:&lt;/p&gt;

&lt;pre&gt;&amp;quot;v=spf1 ~all&amp;quot;&lt;/pre&gt;

&lt;p&gt;All DNS records including SPF are enclosed in double quotes. &lt;code&gt;v=spf1&lt;/code&gt; tells the SPF record validator that this is an SPF record and that it belongs to SPF version 1.&lt;/p&gt;

&lt;p&gt;For practical purposes, always start from an SPF record like above, and then add mechanisms, relating to your hosts and IP addresses, one by one.&lt;/p&gt;

&lt;h2 id="quantifiers"&gt;Quantifiers&lt;/h2&gt;

&lt;p&gt;Before we delve ourselves into mechanisms, let me touch a bit about quantifiers. If you remember the discussion above, I talked about white listing or black listing hosts and IP addresses. To allow (white list) a host or IP address, we append a '+' letter at its beginning e.g., &lt;code&gt;+a&lt;/code&gt;. To disallow (black list) a host or IP address range, we append a '-' letter at its beginning e.g., &lt;code&gt;-a&lt;/code&gt;. An &lt;code&gt;a&lt;/code&gt; mechanism in these examples references the &lt;code&gt;A&lt;/code&gt; record for this domain name. Between allowing and disallowing are two other quantifiers; '~' and '?'. An '~' quantifier (like the one at the beginning of &lt;code&gt;all&lt;/code&gt; mechanism in our first example of an SPF record) means &amp;quot;soft fail&amp;quot;. &lt;em&gt;Soft fail means to accept the emails but put them in the 'Spam' folder and not the user's inbox&lt;/em&gt;. Soft fail is most often used in combination with &lt;code&gt;all&lt;/code&gt; mechanism. An &lt;code&gt;all&lt;/code&gt; mechanism is very powerful as it catches all the hosts and IP addresses that have not been explicitly declared in the preceding mechanisms. Finally, a '?' quantifier tells the SPF record validator to make this mechanism &amp;quot;neutral&amp;quot;. A neutral mechanism is generally interpreted as allowance for that mechanism's host or IP address.&lt;/p&gt;

&lt;p&gt;For practical purposes, I'd suggest that you limit yourself to '+' and '-' to allow and disallow any host or IP address range, and use '~' for the &lt;code&gt;all&lt;/code&gt; mechanism.&lt;/p&gt;

&lt;p&gt;Here is the recap of quantifiers you can use with the mechanisms in your SPF record:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;'+' - pass&lt;/li&gt;
&lt;li&gt;'?' - neutral (generally means pass)&lt;/li&gt;
&lt;li&gt;'~' - soft fail (accept the email but put it in 'Spam' folder)&lt;/li&gt;
&lt;li&gt;'-' - fail&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is not necessary to append '+' (pass) quantifier with mechanisms as it is assumed that a mechanism with no explicit quantifier has a '+' letter prepended. For example, following two SPF records mean one and the same thing:&lt;/p&gt;

&lt;pre&gt;&amp;quot;v=spf1 a ~all&amp;quot;&lt;/pre&gt;
&lt;pre&gt;&amp;quot;v=spf1 +a ~all&amp;quot;&lt;/pre&gt;

&lt;h2 id="mechanisms"&gt;Mechanisms&lt;/h2&gt;

&lt;p&gt;A mechanism (rule) allows you to declare a single IPv4 or IPv6 IP address or an IP address range, a host, an SPF record from another host, an &lt;code&gt;a&lt;/code&gt; record, an &lt;code&gt;mx&lt;/code&gt; (Mail Exchanger) record, and a &lt;code&gt;ptr&lt;/code&gt; record.&lt;/p&gt;

&lt;p&gt;Following is the list of all mechanisms available:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="#ip4-mechanism"&gt;&lt;code&gt;ip4&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#ip6-mechanism"&gt;&lt;code&gt;ip6&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#a-mechanism"&gt;&lt;code&gt;a&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#mx-mechanism"&gt;&lt;code&gt;mx&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#include-mechanism"&gt;&lt;code&gt;include&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#ptr-mechanism"&gt;&lt;code&gt;ptr&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#exists-mechanism"&gt;&lt;code&gt;exists&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#all-mechanism"&gt;&lt;code&gt;all&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We will look at all of them, one by one.&lt;/p&gt;

&lt;h3 id="ip4-mechanism"&gt;ip4 mechanism&lt;/h3&gt;

&lt;p&gt;An &lt;code&gt;ip4&lt;/code&gt; mechanism is used to include an IPv4 address or network range in an SPF record. A network range is specified by first declaring the IPv4 network address and then after a slash ('/'), is declared the length of the network range. All &lt;code&gt;ip4&lt;/code&gt; mechanisms start with &amp;quot;ip4:&amp;quot;.&lt;/p&gt;

&lt;p&gt;For example, following SPF record declares a single IPv4 address:&lt;/p&gt;

&lt;pre&gt;&amp;quot;v=spf1 ip4:127.0.0.1 ~all&amp;quot;&lt;/pre&gt;

&lt;p&gt;Following SPF record declares an &lt;code&gt;ip4&lt;/code&gt; mechanism to include all IP addresses in the 127.0.0.1-127.0.0.255 range:&lt;/p&gt;

&lt;pre&gt;&amp;quot;v=spf1 ip4:127.0.0.1/8 ~all&amp;quot;&lt;/pre&gt;

&lt;p&gt;Following SPF record declares an &lt;code&gt;ip4&lt;/code&gt; mechanism to include all IP addresses in the 127.0.0.1-127.0.255.255 range:&lt;/p&gt;

&lt;pre&gt;&amp;quot;v=spf1 ip4:127.0.0.1/16 ~all&amp;quot;&lt;/pre&gt;

&lt;div class="note"&gt;Since no quantifier was prepended with the &lt;code&gt;ip4&lt;/code&gt; mechanisms in the examples above; a '+' quantifier is assumed. This means that any email originating from these IP addresses should be allowed to &lt;i&gt;pass&lt;/i&gt; successfully.&lt;/div&gt;

&lt;h3 id="ip6-mechanism"&gt;ip6 mechanism&lt;/h3&gt;

&lt;p&gt;An &lt;code&gt;ip6&lt;/code&gt; mechanism is used to include an IPv6 address or network range in an SPF record. All &lt;code&gt;ip6&lt;/code&gt; mechanisms start with &amp;quot;ip6:&amp;quot;.&lt;/p&gt;

&lt;p&gt;Following SPF record declares a single IPv6 address:&lt;/p&gt;

&lt;pre&gt;&amp;quot;v=spf1 ip6:2001:db8:85a3::8a2e:370:7334 ~all&amp;quot;&lt;/pre&gt;

&lt;p&gt;Following SPF record declares an &lt;code&gt;ip6&lt;/code&gt; mechanism to include all IPv6 addresses in the 2001:db8:85a3::8a2e:0000:0000-2001:db8:85a3::8a2e:FFFF:FFFF range:&lt;/p&gt;

&lt;pre&gt;&amp;quot;v=spf1 ip6:2001:db8:85a3::8a2e:370:7334/96 ~all&amp;quot;&lt;/pre&gt;

&lt;h3 id="a-mechanism"&gt;a mechanism&lt;/h3&gt;

&lt;p&gt;An &lt;code&gt;a&lt;/code&gt; mechanism allows us to reference (and include) the IP address(es) of the current domain for which this SPF record exists. Every domain name almost always has an &lt;code&gt;A&lt;/code&gt; record which resolves to the IP address it is hosted at. Larger websites have more than one IP address that an &lt;code&gt;A&lt;/code&gt; record can resolve to. By including and allowing an &lt;code&gt;a&lt;/code&gt; record in the SPF record of your domain name, you are basically allowing any email originating from your domain name to pass.&lt;/p&gt;

&lt;p&gt;For example, following SPF record includes an &lt;code&gt;A&lt;/code&gt; record to allow any emails originating from the IP address of this domain name to pass:&lt;/p&gt;

&lt;pre&gt;&amp;quot;v=spf1 a ~all&amp;quot;&lt;/pre&gt;

&lt;p&gt;If you have another domain name and want to include its &lt;code&gt;A&lt;/code&gt; record so that any email originating from the IP address of that domain name is also passed for your domain name, then use this syntax:&lt;/p&gt;

&lt;pre&gt;&amp;quot;v=spf1 a:anotherdomain.com ~all&amp;quot;&lt;/pre&gt;

&lt;h3 id="mx-mechanism"&gt;mx mechanism&lt;/h3&gt;

&lt;p&gt;An &lt;code&gt;mx&lt;/code&gt; mechanism allows us to include the MX (Mail Exchanger) servers of this domain name in the SPF record. An &lt;code&gt;MX&lt;/code&gt; record in the DNS records of a domain name points to one or more mail servers that are entitled to &lt;i&gt;receive&lt;/i&gt; emails for that domain name. For example, if a person sends an email to an address at Stardeveloper.com, he will most probably send it via an SMTP relay server. That SMTP relay server then fetches the MX record of Stardeveloper.com and resolves it to an IP address. Then it connects to that IP address on the port 25 to deliver that email for Stardeveloper.com. As the admin for Stardeveloper.com, I can change the MX records and point them to any mail server of my choosing which I have configured to receive emails for my domain name.&lt;/p&gt;

&lt;p&gt;Now that we know what an &lt;code&gt;MX&lt;/code&gt; record is, let us see how we declare an &lt;code&gt;mx&lt;/code&gt; mechanism to allow all mail servers who are registered to &lt;i&gt;receive&lt;/i&gt; emails for our domain names to also be given a pass so that if any outgoing email originates from them, it will be passed.&lt;/p&gt;

&lt;p&gt;Following SPF record includes an &lt;code&gt;mx&lt;/code&gt; mechanism to allow any emails originating from the &lt;code&gt;MX&lt;/code&gt; servers of this domain name to pass:&lt;/p&gt;

&lt;pre&gt;&amp;quot;v=spf1 mx ~all&amp;quot;&lt;/pre&gt;

&lt;p&gt;You can also include &lt;code&gt;MX&lt;/code&gt; records for another domain name like the syntax we saw earlier for &lt;code&gt;A&lt;/code&gt; record:&lt;/p&gt;

&lt;pre&gt;&amp;quot;v=spf1 mx:anotherdomain.com ~all&amp;quot;&lt;/pre&gt;

&lt;h3 id="include-mechanism"&gt;include mechanism&lt;/h3&gt;

&lt;p&gt;An &lt;code&gt;include&lt;/code&gt; mechanism is used to include a policy (SPF record) from another host or domain name. You will use this if your domain's emails also go through 3rd party SMTP servers over which you have no control. The 3rd party has its own policy (SPF record) for their SMTP servers/domain names. By including their SPF record in the SPF record of your domain name, you are allowing all emails to pass which are allowed to pass by that domain name. In other words, all emails originating from 3rd party's SMTP servers will be passed.&lt;/p&gt;

&lt;p&gt;Following SPF record includes a policy (SPF record) from a third party's domain name:&lt;/p&gt;

&lt;pre&gt;&amp;quot;v=spf1 include:anotherdomain.com ~all&amp;quot;&lt;/pre&gt;

&lt;p&gt;Following is a real World example of an &lt;code&gt;include&lt;/code&gt; mechanism to allow emails going through Google's SMTP servers to be passed:&lt;/p&gt;

&lt;pre&gt;&amp;quot;v=spf1 include:aspmx.googlemail.com ~all&amp;quot;&lt;/pre&gt;

&lt;p&gt;If you plan to use Google Apps with your domain name, then you must include this mechanism in the SPF record of your domain name: &lt;code&gt;include:aspmx.googlemail.com&lt;/code&gt;. Learn more about &lt;a href="http://www.stardeveloper.com/articles/what-is-sender-policy-framework/#example-spf-record" title="How Stardeveloper uses its SPF records to allow outgoing emails from Google Apps" onclick="_gaq.push(['_trackEvent', 'internal-movement', '/articles/spf-record-syntax : /articles/what-is-spf', 'article']);"&gt;how to setup SPF records for Google Apps&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id="ptr-mechanism"&gt;ptr mechanism&lt;/h3&gt;

&lt;p&gt;A &lt;code&gt;ptr&lt;/code&gt; mechanism allows you to include a &lt;code&gt;PTR&lt;/code&gt; (pointer) record for a domain name. A &lt;code&gt;PTR&lt;/code&gt; record is used in reverse DNS lookup. If your domain name has &lt;code&gt;A&lt;/code&gt; and &lt;code&gt;PTR&lt;/code&gt; records set correctly, an &lt;code&gt;A&lt;/code&gt; record will resolve to an IP address, and that IP address can be &lt;i&gt;reverse looked up&lt;/i&gt; back to the original domain name using &lt;code&gt;PTR&lt;/code&gt; record.&lt;/p&gt;

&lt;p&gt;Following SPF record uses a &lt;code&gt;ptr&lt;/code&gt; mechanism to include a &lt;code&gt;PTR&lt;/code&gt; record for this domain name:&lt;/p&gt;

&lt;pre&gt;&amp;quot;v=spf1 ptr ~all&amp;quot;&lt;/pre&gt;

&lt;p&gt;To include a &lt;code&gt;PTR&lt;/code&gt; record of another domain name, you will use this syntax:&lt;/p&gt;

&lt;pre&gt;&amp;quot;v=spf1 ptr:anotherdomain.com ~all&amp;quot;&lt;/pre&gt;

&lt;div class="note"&gt;It is recommended that you do not unnecessarily use a &lt;code&gt;ptr&lt;/code&gt; mechanism unless you have to because it results in unnecessary DNS lookups.&lt;/div&gt;

&lt;h3 id="exists-mechanism"&gt;exists mechanism&lt;/h3&gt;

&lt;p&gt;An &lt;code&gt;exists&lt;/code&gt; mechanism is used for checking if an &lt;code&gt;A&lt;/code&gt; record &lt;i&gt;exists&lt;/i&gt; for a given domain name. And if it exists, the email is allowed to pass.&lt;/p&gt;

&lt;p&gt;It does not matter if the IP address of that domain name matches the originating IP address for this email or not. What matters is that, an &lt;code&gt;A&lt;/code&gt; record should &lt;i&gt;exist&lt;/i&gt; and that's all.&lt;/p&gt;

&lt;p&gt;Following SPF record includes an &lt;code&gt;exists&lt;/code&gt; mechanism for anotherdomain.com:&lt;/p&gt;

&lt;pre&gt;&amp;quot;v=spf1 exists:anotherdomain.com ~all&amp;quot;&lt;/pre&gt;

&lt;p&gt;Personally, I am not sure why if an &lt;code&gt;A&lt;/code&gt; record exists for a domain name, you will allow this email to pass. But then, there must be some reason why this mechanism exists, no?&lt;/p&gt;

&lt;h3 id="all-mechanism"&gt;all mechanism&lt;/h3&gt;

&lt;p&gt;An &lt;code&gt;all&lt;/code&gt; mechanism is used to declare a rule for hosts and IP addresses that have &lt;i&gt;not&lt;/i&gt; matched with the preceding mechanisms. All SPF records almost always have an &lt;code&gt;all&lt;/code&gt; mechanism declared at the end of the SPF record.&lt;/p&gt;

&lt;p&gt;What you should do is to declare one or more mechanisms that if matched, will allow the email to pass (white list). At the end you should declare an &lt;code&gt;all&lt;/code&gt; mechanism which should be quantified with an '~' to soft fail the rest.&lt;/p&gt;

&lt;p&gt;Following SPF record declares an &lt;code&gt;all&lt;/code&gt; mechanism to soft fail all emails i.e., no legitimate emails can originate for this domain name:&lt;/p&gt;

&lt;pre&gt;&amp;quot;v=spf1 ~all&amp;quot;&lt;/pre&gt;

&lt;p&gt;Following SPF record will fail all emails originating for this domain name:&lt;/p&gt;

&lt;pre&gt;&amp;quot;v=spf1 -all&amp;quot;&lt;/pre&gt;

&lt;p&gt;Following SPF record will &lt;i&gt;pass&lt;/i&gt; all emails with this domain name in the 'From' address of the email, no matter from where it originted:&lt;/p&gt;

&lt;pre&gt;&amp;quot;v=spf1 all&amp;quot;&lt;/pre&gt;

&lt;div class="note"&gt;The example above to allow all emails to pass is for demonstration purposes only. You obviously will not be using this in real practice.&lt;/div&gt;

&lt;h2&gt;SPF record generating tips&lt;/h2&gt;

&lt;p&gt;First create a white list of hosts and IP addresses from which legitimate emails can originate for your domain name. You can always look at the example &lt;a href="http://www.stardeveloper.com/articles/what-is-sender-policy-framework/#example-spf-record" title="Details of the SPF record for Stardeveloper" onclick="_gaq.push(['_trackEvent', 'internal-movement', '/articles/spf-record-syntax : /articles/what-is-spf', 'article']);"&gt;SPF record of Stardeveloper.com&lt;/a&gt; to have a look.&lt;/p&gt;

&lt;p&gt;To create an SPF record for this list, start with a simple SPF record which soft fails every email like this:&lt;/p&gt;

&lt;pre&gt;&amp;quot;v=spf1 ~all&amp;quot;&lt;/pre&gt;

&lt;p&gt;Then go through the white list you created, one by one, and using the &lt;a href="#mechanisms"&gt;mechanisms'&lt;/a&gt; syntax we learned above, add the mechanisms to your SPF record.&lt;/p&gt;

&lt;p&gt;My advice is to always include the &lt;code&gt;A&lt;/code&gt; record in the SPF record for your domain name. Rest, you can decide.&lt;/p&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;In this article, we learned the SPF record syntax. We learned about quantifiers and mechanisms which collectively formulate a policy for a domain name. I hope the information in this article will be sufficient to help you setup correct SPF record for your domain name.&lt;/p&gt;

&lt;p&gt;Good luck!&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.stardeveloper.com/~ff/StardevelopercomArticleHeadlines?a=AWhpXjCDYCU:Lwq80HmkT5w:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/StardevelopercomArticleHeadlines?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.stardeveloper.com/~ff/StardevelopercomArticleHeadlines?a=AWhpXjCDYCU:Lwq80HmkT5w:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/StardevelopercomArticleHeadlines?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/StardevelopercomArticleHeadlines/~4/AWhpXjCDYCU" height="1" width="1"/&gt;</description>
<guid isPermaLink="false"><![CDATA[http://www.stardeveloper.com/articles/spf-record-syntax/]]></guid>
<author>Faisal Khan</author>
<pubDate>Fri, 26 Feb 2010 06:51:00 GMT</pubDate>
<atom:link href="http://feeds.stardeveloper.com/StardevelopercomArticleHeadlines" rel="self" type="application/rss+xml" /><feedburner:origLink>http://www.stardeveloper.com/articles/spf-record-syntax/</feedburner:origLink></item>
<item>
<title>What is Sender Policy Framework?</title>
<link>http://feeds.stardeveloper.com/~r/StardevelopercomArticleHeadlines/~3/EQzbjw2kQTw/</link>
<description>&lt;p&gt;SPF stands for '&lt;em&gt;Sender Policy Framework&lt;/em&gt;' which is an open standard to prevent the abuse of your domain name by someone else pretending to be you by using your email address or domain name in the 'From' field of his email.&lt;/p&gt;

&lt;p&gt;How many times do you get bounced email back in your inbox for emails containing your email address in the 'From' field, selling products or containing links to indecent websites? You never sent these emails. Yet someone has picked your email or a fake email using your website's domain name to send spam to thousands of others users using your email address to bypass the filters on their inboxes and to use your repute and recognition to make the end-user give undeserved attention to their spam links.&lt;/p&gt;

&lt;h2&gt;How does SPF work?&lt;/h2&gt;

&lt;p&gt;SPF works by making use of a list of &lt;a href="http://www.stardeveloper.com/articles/convert-ip-address-to-long/" onclick="_gaq.push(['_trackEvent', 'internal-movement', '/articles/what-is-spf : /articles/convert-ip-address-to-long', 'article']);" title="What is an IP address?"&gt;IP addresses&lt;/a&gt; that you specifically allow from which a legitimate email can originate for your domain name. For your website you have to make a list of IP addresses (or host names) from which legitimate emails can be sent for your domain name. This list should contain the IP addresses of your website (the A records) and the IP addresses of your SMTP servers (all of them). If you are using BlackBerry to send emails for your website or company, you will have to include their IP addresses in this list as well.&lt;/p&gt;

&lt;p&gt;Now it is not easy to know the IP addresses of all servers from where the legitimate emails can originate for your domain name, you can make use of &lt;a href="http://www.stardeveloper.com/articles/spf-record-syntax/" onclick="_gaq.push(['_trackEvent', 'internal-movement', '/articles/what-is-spf : /articles/spf-record-syntax', 'article']);" title="SPF Record Syntax"&gt;SPF record syntax&lt;/a&gt; to create a &lt;i&gt;policy&lt;/i&gt; to include IP addresses by using host names and domain names instead of plain IP addresses in your SPF record. You can also &lt;i&gt;include&lt;/i&gt; other domains' SPF records. The cool thing with SPF's syntax is that with very little effort you can comprehensively include all the servers without needing to hard code any single IP address at all.&lt;/p&gt;

&lt;p&gt;Once a list of IP addresses and host names has been setup for your domain name, then the next time an authorized person tries to send an email using the 'From' address of your domain name e.g., fakedname@yourwebsite.com, the MX (Mail Exchanger) server receiving this email will lookup SPF record for your domain by checking the DNS records of your domain name. When it finds an SPF record, it will go through the list of IP addresses and host names, one by one, to see if this email is originating from the &lt;i&gt;white list&lt;/i&gt; of IP addresses allowed to send email on your behalf or not. Since the originating email in this case did not originate from an authorized IP address, the receiving mail server will silently place this email in the 'Spam' folder, and not the user's 'Inbox'.&lt;/p&gt;

&lt;p&gt;This is how SPF prevents misuse of your domain name by unauthorized persons.&lt;/p&gt;

&lt;div class="note"&gt;This of course implies that you have to have your own domain name, for example, yourwebsite.com, and an email address like yourname@yourwebsite.com. If you are using Gmail or Yahoo and have email address like yourname@gmail.com, then you do not need to setup an SPF record; because it is already set by those email providers.&lt;/div&gt;

&lt;h2 id="example-spf-record"&gt;An example SPF record&lt;/h2&gt;

&lt;p&gt;The SPF record for &lt;a href="http://www.stardeveloper.com/" title="Stardeveloper.com" onclick="_gaq.push(['_trackEvent', 'internal-movement', 'what-is-spf : home-page', 'article']);"&gt;Stardeveloper&lt;/a&gt; looks like this:&lt;/p&gt;

&lt;pre&gt;&amp;quot;v=spf1 a include:aspmx.googlemail.com include:srs.bis.eu.blackberry.com ~all&amp;quot;&lt;/pre&gt;

&lt;h2&gt;Explanation&lt;/h2&gt;

&lt;pre&gt;v=spf1&lt;/pre&gt;

&lt;p&gt;An SPF record always begings with &lt;code&gt;v=spf1&lt;/code&gt;. This tells the SPF record validator that this SPF record's syntax belongs to version 1 of Sender Policy Framework.&lt;/p&gt;

&lt;pre&gt;a&lt;/pre&gt;

&lt;p&gt;Next, the SPF record contains an &lt;code&gt;a&lt;/code&gt; which means an 'A' record for the domain name. What this means is that legitimate email can originate for Stardeveloper.com from the IP address it is hosted at. Note: the IP address has not been hard coded for the domain name, instead an &lt;code&gt;a&lt;/code&gt; record has been specified using &lt;a href="http://www.stardeveloper.com/articles/spf-record-syntax/" onclick="_gaq.push(['_trackEvent', 'internal-movement', '/articles/what-is-spf : /articles/spf-record-syntax', 'article']);" title="SPF Record Syntax"&gt;SPF record syntax&lt;/a&gt;. If Stardeveloper is relocated to another IP address, the 'A' record will automatically point to the new IP address without requiring any change in the SPF record for this domain name.&lt;/p&gt;

&lt;pre&gt;include:aspmx.googlemail.com&lt;/pre&gt;

&lt;p&gt;Since, Stardeveloper is using Google Apps for email hosting, I have included Google Apps' SPF record as part of the SPF record of Stardeveloper.com to make sure that any email that is sent through Google's SMTP servers is marked as legitimate.&lt;/p&gt;

&lt;pre&gt;include:srs.bis.eu.blackberry.com&lt;/pre&gt;

&lt;p&gt;I am using &lt;a href="http://blog.stardeveloper.com/tagged/BlackBerry" title="Faisal's blog posts about BlackBerry handsets" onclick="_gaq.push(['_trackEvent', 'internal-movement', '/articles/what-is-spf : blog/blackberry', 'article']);"&gt;BlackBerry&lt;/a&gt; Bold 9700 as my mobile device. I use it to send and receive emails. To be able to mark all emails sent through my BlackBerry device that make use of BlackBerry's SMTP servers, I have included their SPF records from their domain name.&lt;/p&gt;

&lt;div class="tip"&gt;If you are based in North America, then you should change the 'eu' with 'na' to include BlackBerry's North American SMTP servers, that is, &lt;code&gt;include:srs.bis.na.blackberry.com&lt;/code&gt; .&lt;/div&gt;

&lt;pre&gt;~all&lt;/pre&gt;

&lt;p&gt;The final mechanism beginning with a tilde '~' suggests a 'soft fail' for emails &lt;strong&gt;not&lt;/strong&gt; being sent from authorized IP address. Soft fail means that emails originating from unauthorized IP addresses will be received by mail servers (MX) but will be placed in 'Spam' folders and not users' inbox. If this syntax had been &lt;code&gt;-all&lt;/code&gt;, it would have meant 'hard fail'. Hard fail means to reject all emails originating from unlisted IP addresses straight away. Since Google recommends a soft fail based SPF syntax, Stardeveloper uses this syntax and so should you (unless of course if you know what you are doing).&lt;/p&gt;

&lt;h2&gt;How to check the SPF record for a domain name?&lt;/h2&gt;

&lt;p&gt;You can use the &lt;a href="http://tools.bevhost.com/cgi-bin/dnslookup" title="SPF record viewer" onclick="_gaq.push(['_trackEvent', 'external-movement', '/articles/what-is-spf : tools.bevhost.com/spf-record-viewer', 'article']);"&gt;SPF record checking tool&lt;/a&gt; here. Just enter the domain name of your website (or any other to just have a look how they have setup their SPF records), and submit the form.&lt;/p&gt;

&lt;h2&gt;Should you have an SPF record for your website?&lt;/h2&gt;

&lt;p&gt;It is absolutely important for you to have an SPF record for your domain name. You must prevent the abuse of your domain name. You must not let your Uncle get an email from an unauthorized person claiming as you and suggesting your Uncle to visit his spam website. And this becomes even more important if you have a repute online.&lt;/p&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;In this article, we learned what is an SPF record and how it works. We looked at a sample SPF record and learned how simple the SPF record syntax can be to set one up for one's website.&lt;/p&gt;

&lt;h2&gt;Read Next&lt;/h2&gt;

&lt;p&gt;Now that you know what is SPF and how you can use it to protect your domain name from being used by spammers, move on to the next article in this series to learn about &lt;a href="http://www.stardeveloper.com/articles/spf-record-syntax/" title="SPF Record Syntax" onclick="_gaq.push(['_trackEvent', 'internal-movement', '/articles/what-is-spf : /articles/spf-record-syntax', 'article']);"&gt;SPF record syntax&lt;/a&gt; and to use this syntax to create an SPF record for your website.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.stardeveloper.com/~ff/StardevelopercomArticleHeadlines?a=EQzbjw2kQTw:sjdM8SktJxw:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/StardevelopercomArticleHeadlines?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.stardeveloper.com/~ff/StardevelopercomArticleHeadlines?a=EQzbjw2kQTw:sjdM8SktJxw:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/StardevelopercomArticleHeadlines?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/StardevelopercomArticleHeadlines/~4/EQzbjw2kQTw" height="1" width="1"/&gt;</description>
<guid isPermaLink="false"><![CDATA[http://www.stardeveloper.com/articles/what-is-sender-policy-framework/]]></guid>
<author>Faisal Khan</author>
<pubDate>Mon, 22 Feb 2010 09:19:00 GMT</pubDate>
<atom:link href="http://feeds.stardeveloper.com/StardevelopercomArticleHeadlines" rel="self" type="application/rss+xml" /><feedburner:origLink>http://www.stardeveloper.com/articles/what-is-sender-policy-framework/</feedburner:origLink></item>
<item>
<title>Convert IP Address to Long</title>
<link>http://feeds.stardeveloper.com/~r/StardevelopercomArticleHeadlines/~3/5Sc1UWqoO34/</link>
<description>&lt;p&gt;An IP address is a numerical address that is assigned to your computer the moment it connects to a network. Whenever you access a website on internet, a request is sent from your computer containing IP address of your computer, the address to which the website's data should be sent back to. This IP address can be used for logging, tracking stats, allowing (white lists) or blocking (black lists) content, and for a variety of other reasons by the website administrator.&lt;/p&gt;

&lt;p&gt;ASP.NET makes it very easy to develop &lt;a href="http://www.stardeveloper.com/articles/display.html?article=2009071801&amp;amp;page=1" title="Introduction to Developing HTTP Modules" onclick="_gaq.push(['_trackEvent', 'internal-movement', '/articles/convert-ip-address-to-long : /articles/introduction-to-developing-http-modules', 'article']);"&gt;HTTP Modules&lt;/a&gt; and &lt;a href="http://www.stardeveloper.com/#ADO.NET" title="Articles on database application development" onclick="_gaq.push(['_trackEvent', 'internal-movement', '/articles/convert-ip-address-to-long : home-page', 'article']);"&gt;database driven web applications&lt;/a&gt; to analyze and store these IP addresses in the database. A convenient property made available to all ASP.NET applications as part of an HTTP request is &lt;code&gt;HttpRequest.UserHostAddress&lt;/code&gt; property which will return a &lt;code&gt;string&lt;/code&gt; representation of the user's IP address.&lt;/p&gt;

&lt;h2&gt;Do not store IP Addresses as strings&lt;/h2&gt;

&lt;p&gt;The problem here is that to analyze or store this IP address as &lt;code&gt;string&lt;/code&gt; is not the most efficient or recommended method. Not only does it take more space (as much as 15 bytes) to store data, sorting and indexing this data is inefficient.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It takes 15 bytes (&lt;code&gt;varchar(15)&lt;/code&gt;) to store an IP address like &amp;quot;255.255.255.255&amp;quot;.&lt;/li&gt;
&lt;li&gt;Sorting is inefficient because the values will be sorted as string literals.&lt;/li&gt;
&lt;li&gt;It is not possible to find an IP address e.g., &amp;quot;255.255.255.127&amp;quot; in a &lt;i&gt;block&lt;/i&gt; of IP addresses e.g., &amp;quot;255.255.255.0&amp;quot; - &amp;quot;255.255.255.255&amp;quot;. You will have to use inefficient SQL queries like:
&lt;pre&gt;&amp;quot;SELECT * FROM [IPAddresses] WHERE [IPAddress] LIKE '255.255.255.%'&amp;quot;&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, what should you do?&lt;/p&gt;

&lt;h2&gt;Solution: Convert IP Addresses to Long values&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;The solution is to &lt;i&gt;convert&lt;/i&gt; an IP address into an integer.&lt;/em&gt;. In most programming languages, the integer is declared as &lt;code&gt;long&lt;/code&gt; to provide 8 bytes of space to the variable. In C#, an 8 byte long value is declared using &lt;code&gt;long&lt;/code&gt; keyword. In T-SQL (i.e., for SQL Server), an 8 byte long value is declared as &lt;code&gt;bigint&lt;/code&gt;. Here is why storing IP addresses as &lt;code&gt;long&lt;/code&gt; (or &lt;code&gt;bigint&lt;/code&gt; in T-SQL) is more efficient:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It takes only 8 bytes to store an IP address as &lt;code&gt;long&lt;/code&gt;. An IP address like &amp;quot;255.255.255.255&amp;quot; is stored as 4294967295. The code to do this conversion, both in C# and T-SQL, will be looked upon later in this tutorial.&lt;/li&gt;
&lt;li&gt;Sorting is extremely efficient as it is very easy to do the sorting on numerical data like 4294967295 than string literals like &amp;quot;255.255.255.255&amp;quot;.&lt;/li&gt;
&lt;li&gt;You can very easily find if a given IP address exists in a block of IP addresses using the query:
&lt;pre&gt;&amp;quot;SELECT * FROM [IPAddresses] WHERE
	[IPAddress] BETWEEN [IPAddressBlock1] AND [IPAddressBlock2]&amp;quot;&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, we will look at the code to convert a &lt;code&gt;string&lt;/code&gt; literal IP address (like &amp;quot;255.255.255.255&amp;quot;) to a numerical value (like 4294967295) and back.&lt;/p&gt;

&lt;h2&gt;Converting IP Addresses to Long Values and Back in C#&lt;/h2&gt;

&lt;p&gt;To convert a &lt;code&gt;string&lt;/code&gt; IP address to a long value, we will use the &lt;code&gt;ConvertIPToLong()&lt;/code&gt; method as shown below. We first convert the IP address &lt;code&gt;string&lt;/code&gt; literal to &lt;code&gt;System.Net.IPAddress&lt;/code&gt;. Then we convert this IP address to an array of 4 bytes by splitting this IP address using the dot (&amp;quot;.&amp;quot;) letter. It then converts the 4 bytes array to a single &lt;code&gt;long&lt;/code&gt; value.&lt;/p&gt;

&lt;pre&gt;
/// &amp;lt;summary&amp;gt;
/// Author: Faisal Khan (http://www.stardeveloper.com)
/// &amp;lt;/summary&amp;gt;
public static long ConvertIPToLong(string ipAddress)
{
	System.Net.IPAddress ip;

	if (System.Net.IPAddress.TryParse(ipAddress, out ip))
	{
		byte[] bytes = ip.GetAddressBytes();

		return (long)((bytes[0] &amp;lt;&amp;lt; 24) | (bytes[1] &amp;lt;&amp;lt; 16) |
			(bytes[2] &amp;lt;&amp;lt; 8) | bytes[3]);
	}
	else
		return 0;
}&lt;/pre&gt;

&lt;p&gt;Now to convert an IP address &lt;code&gt;long&lt;/code&gt; value back to its &lt;code&gt;string&lt;/code&gt; representation, we will use the &lt;code&gt;ConvertLongToIP()&lt;/code&gt; method as shown below:&lt;/p&gt;

&lt;pre&gt;
/// &amp;lt;summary&amp;gt;
/// Author: Faisal Khan (http://www.stardeveloper.com)
/// &amp;lt;/summary&amp;gt;
public static string ConvertLongToIP(long ipLong)
{
	StringBuilder b = new StringBuilder();
	long tempLong, temp;

	tempLong = ipLong;
	temp = tempLong / (256 * 256 * 256);
	tempLong = tempLong - (temp * 256 * 256 * 256);
	b.Append(Convert.ToString(temp)).Append(&amp;quot;.&amp;quot;);
	temp = tempLong / (256 * 256);
	tempLong = tempLong - (temp * 256 * 256);
	b.Append(Convert.ToString(temp)).Append(&amp;quot;.&amp;quot;);
	temp = tempLong / 256;
	tempLong = tempLong - (temp * 256);
	b.Append(Convert.ToString(temp)).Append(&amp;quot;.&amp;quot;);
	temp = tempLong;
	tempLong = tempLong - temp;
	b.Append(Convert.ToString(temp));

	return b.ToString().ToLower();
}&lt;/pre&gt;

&lt;h2&gt;Converting IP Addresses to Bigint Values and Back in T-SQL&lt;/h2&gt;

&lt;p&gt;We will use &lt;code&gt;ConvertIPToLong()&lt;/code&gt; function to convert &lt;code&gt;varchar(15)&lt;/code&gt; based IP address to a &lt;code&gt;bigint&lt;/code&gt; value as shown below:&lt;/p&gt;

&lt;pre&gt;
' Author: Faisal Khan (http://www.stardeveloper.com)
CREATE FUNCTION [dbo].[ConvertIPToLong](@IP varchar(15))
RETURNS bigint
AS
BEGIN
	DECLARE @Long bigint
	SET @Long = CONVERT(bigint, PARSENAME(@IP, 4)) * 256 * 256 * 256 +
		CONVERT(bigint, PARSENAME(@IP, 3)) * 256 * 256 +
		CONVERT(bigint, PARSENAME(@IP, 2)) * 256 +
		CONVERT(bigint, PARSENAME(@IP, 1))

	RETURN (@Long)
END&lt;/pre&gt;

&lt;p&gt;Now, to convert this &lt;code&gt;bigint&lt;/code&gt; value back to its &lt;code&gt;varchar(15)&lt;/code&gt; representation, we will use the &lt;code&gt;ConvertLongToIP()&lt;/code&gt; function as shown below:&lt;/p&gt;

&lt;pre&gt;
' Author: Faisal Khan (http://www.stardeveloper.com)
CREATE FUNCTION [dbo].[ConvertLongToIP](@Long bigint)
RETURNS varchar(15)
AS
BEGIN
	DECLARE @IP varchar(15)
	DECLARE @TempLong bigint
	DECLARE @Temp bigint

	SET @TempLong = @Long
	SET @Temp = @TempLong / (256 * 256 * 256)
	SET @TempLong = @TempLong - (@Temp * 256 * 256 * 256)
	SET @IP = CONVERT(varchar(3), @Temp) + '.'
	SET @Temp = @TempLong / (256 * 256)
	SET @TempLong = @TempLong - (@Temp * 256 * 256)
	SET @IP = @IP + CONVERT(varchar(3), @Temp) + '.'
	SET @Temp = @TempLong / 256
	SET @TempLong = @TempLong - (@Temp * 256)
	SET @IP = @IP + CONVERT(varchar(3), @Temp) + '.'
	SET @Temp = @TempLong
	SET @TempLong = @TempLong - @Temp
	SET @IP = @IP + CONVERT(varchar(3), @Temp)

	RETURN (@IP)
END &lt;/pre&gt;

&lt;p&gt;After you have created these functions in your database, you can run the following SQL code to test these functions:&lt;/p&gt;

&lt;pre&gt;SELECT [dbo].ConvertIPToLong('255.255.255.255'), [dbo].ConvertLongToIP(4294967295)&lt;/pre&gt;

&lt;p&gt;You should create these functions in your C# libraries and in SQL Server databases and use them whenever you want to store or use an IP address in your code or database.&lt;/p&gt;

&lt;h2&gt;Final Words&lt;/h2&gt;

&lt;p&gt;I have very succinctly described the code to convert an IP address from a &lt;code&gt;string&lt;/code&gt; value to &lt;code&gt;long&lt;/code&gt; and back. I hope this code will be useful to you in your web and database application development. Good luck!&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.stardeveloper.com/~ff/StardevelopercomArticleHeadlines?a=5Sc1UWqoO34:OH9tshaSVaw:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/StardevelopercomArticleHeadlines?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.stardeveloper.com/~ff/StardevelopercomArticleHeadlines?a=5Sc1UWqoO34:OH9tshaSVaw:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/StardevelopercomArticleHeadlines?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/StardevelopercomArticleHeadlines/~4/5Sc1UWqoO34" height="1" width="1"/&gt;</description>
<guid isPermaLink="false"><![CDATA[http://www.stardeveloper.com/articles/convert-ip-address-to-long/]]></guid>
<author>Faisal Khan</author>
<pubDate>Sun, 27 Dec 2009 08:48:00 GMT</pubDate>
<atom:link href="http://feeds.stardeveloper.com/StardevelopercomArticleHeadlines" rel="self" type="application/rss+xml" /><feedburner:origLink>http://www.stardeveloper.com/articles/convert-ip-address-to-long/</feedburner:origLink></item>
<item>
<title>Introduction to Developing HTTP Modules in ASP.NET</title>
<link>http://feeds.stardeveloper.com/~r/StardevelopercomArticleHeadlines/~3/gzdvaqfZZr4/display.html</link>
<description>&lt;p&gt;&lt;b&gt;Introduction&lt;/b&gt;&lt;br /&gt;
In ASP.NET, an HTTP Module is a class that implements the &lt;code&gt;IHttpModule&lt;/code&gt; interface. By doing that it can listen to and handle events in the web request handling pipeline. They are the equivalent of &amp;#39;ISAPI Filters&amp;#39; in IIS and &amp;#39;Filters&amp;#39; in JSP. They are used for multiple purposes from authenticating a request to modifying the response and logging the request. In this tutorial, we will learn:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Common uses of HTTP Modules&lt;/li&gt;
&lt;li&gt;Web Request Handling Pipeline&lt;/li&gt;
&lt;li&gt;Structure of an HTTP Module&lt;/li&gt;
&lt;li&gt;Creating your first HTTP Module&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;b&gt;Common Uses of HTTP Modules&lt;/b&gt;&lt;br /&gt;
Following is a noncomprehensive list of common uses of HTTP Modules:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Authentication&lt;/b&gt; - To authenticate a user. For example, you can place a cookie in the user's browser once he has logged in. Next time when the user visits the website, his session will have timed out. An HTTP Module can fetch the cookie and log the user back in by retrieving and matching the cookie string against user data in the database, without the user having to enter his username/password on the website. This can provide a smooth experience to the user who will never come to know how he has been logged back in automatically.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Authorization&lt;/b&gt; - To protect access to restricted resources on the website. An HTTP Module can authenticate the user accessing the resource and if the user is not listed in the roles allowed to access this resource, then the user can be redirected back to a &amp;quot;login&amp;quot; page.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Protection against Denial of Service Attacks&lt;/b&gt; - An HTTP Module can maintain an internal list of &lt;a href="http://www.stardeveloper.com/articles/convert-ip-address-to-long/" title="What are IP addresses and how to convert an IP address to an integer value"&gt;IP addresses&lt;/a&gt; accessing the website along with the hits the website is receiving from each of them. When an IP address is noted to be sending too many requests &lt;em&gt;out of proportion&lt;/em&gt; to the rest of the IP addresses, that IP address can be temporarily blocked from accessing the website.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;HTTP Compression&lt;/b&gt; - To compress the text output of web pages using &lt;a href="http://www.stardeveloper.com/articles/display.html?article=2007110401&amp;amp;page=1"&gt;&lt;code&gt;Gzip&lt;/code&gt;&lt;/a&gt; and &lt;a href="http://www.stardeveloper.com/articles/display.html?article=2007110401&amp;amp;page=1"&gt;&lt;code&gt;Deflate&lt;/code&gt;&lt;/a&gt; algorithms. Compression can not only substantially reduce the bandwidth usage of a website, it can also make the pages appear faster in the users' browsers because of smaller sizes of compressed pages that are sent over the internet.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Encryption&lt;/b&gt; - To encrypt an outgoing response into encrypted text.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Caching&lt;/b&gt; - To cache commonly accessed content into an in-memory cache. This can be applied to static as well as dynamic generated content. Again an internal list can be used to gather statistics first as to which content is accessed more often than others. Then the popular content can be cached.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Collecting User Information&lt;/b&gt; - To get the user IP address and match it against an internal database of IP addresses along with names of countries. The HTTP Module can then pass the fetched country name (or country code) silently to the request handlers which can then display it as a country flag to the user. This is useful for not only providing customized experience to the user, you can also use it to display different content (e.g., ads) to users from different countries.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Modifying Headers&lt;/b&gt; - To modify the outgoing headers. For example, you can use it to tell the client browser when the requested resource was last modified and so on. You can send the headers for static content to be cached in the client browser and intermediate proxy servers, more often than for example dynamic content.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Formatting Output&lt;/b&gt; - To transform XML files with XSL stylesheets on the fly. So when the user accesses an XML file on your website directly, he/she will be served an HTML transformation of the XML file, displaying the content in a more pleasant fashion.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Replacing Content&lt;/b&gt; - To use regular expressions to parse and replace content in the response generated by the request handler. For example, to &lt;em&gt;highlight&lt;/em&gt; words in the outgoing HTML content matching keywords that a user entered in the search engine e.g., Google, to visit your website. This will improve the experience of a person on your website who entered some keywords in Google and found your website among the ones that Google displayed. Now when he visited your website he sees his keywords highlighted within the text of that page.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Logging&lt;/b&gt; - To log requests in a file or a database. Some examples:-
	&lt;ul&gt;
	&lt;li&gt;To log hits that your website is getting every hour. An ASP.NET page can be used to display these hits in a chart to you providing you with a quick snapshot of the activity on your website.&lt;/li&gt;
	&lt;li&gt;To scan the &lt;code&gt;Status Code&lt;/code&gt; e.g., 500, generated by a resource downstream, and log it in the database. An ASP.NET page again can be used to view in the form of a chart, when and how many 500 HTTP errors were generated on the website and by which resource.&lt;/li&gt;
	&lt;li&gt;To log bandwidth that your website is using, day in and day out.&lt;/li&gt;
	&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div align="center" style="background-color: #F7F7F7;"&gt;&lt;b&gt;Note:&lt;/b&gt; What you can do with HTTP Modules is only limited by your imagination. Soon when you are up to speed with HTTP Modules, you will be developing ones for needs you had never thought you &lt;i&gt;can&lt;/i&gt; be developing for, before.&lt;/div&gt;

&lt;p&gt;On the next page, we will look at the events in the &amp;#39;Web Request Handling Pipeline&amp;#39;.&lt;/p&gt;&lt;p&gt;&lt;b&gt;Web Request Handling Pipeline&lt;/b&gt;&lt;br /&gt;
In ASP.NET, there is a series of events that is raised before a request is handed over to a &lt;b&gt;request handler&lt;/b&gt; to execute. And on its way back to the client, another series of events is raised. This model is what I refer to as the &amp;#39;&lt;em&gt;Web Request Handling Pipeline&lt;/em&gt;&amp;#39;. The list of these events, in the order that they are fired from the moment a request is received to the moment it is disposed, is given below with brief description:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;BeginRequest&lt;/code&gt; - Fired as the first event when ASP.NET responds to a request.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;AuthenticateRequest&lt;/code&gt; - Occurs when the identity of the user is being established.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PostAuthenticateRequest&lt;/code&gt; - Occurs when the identity of the user has been established.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;AuthorizeRequest&lt;/code&gt; - Occurs when the request is being authorized for this user.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PostAuthorizeRequest&lt;/code&gt; - Occurs when the request has been authorized for this user.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ResolveRequestCache&lt;/code&gt; - Occurs when the request is being examined for the fact that the requested resource be sent directly from the cache or not.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PostResolveRequestCache&lt;/code&gt; - Occurs when the requested resource is being sent directly from the cache and the &lt;em&gt;request handler will not be called to process this request&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;MapRequestHandler&lt;/code&gt; - Occurs when the request is being mapped to an appropriate request handler. This event is only raised in IIS 7.0 when it is run in &lt;b&gt;integrated mode&lt;/b&gt; with .NET Framework 3.0 or above.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PostMapRequestHandler&lt;/code&gt; - Occurs when appropriate request handler has been mapped with the request.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;AcquireRequestState&lt;/code&gt; - Occurs when state associated with the request is being acquired.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PostAcquireRequestState&lt;/code&gt; - Occurs when state associated with the request has been acquired.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PreRequestHandlerExecute&lt;/code&gt; - Occurs just before request handler (e.g., an ASP.NET page) is handed over control for this request. In the tutorial on &amp;quot;&lt;a href="http://www.stardeveloper.com/articles/display.html?article=2007110401&amp;page=1"&gt;Enabling Gzip and Deflate HTTP Compression in ASP.NET pages&lt;/a&gt;&amp;quot;, this event is handled to enable HTTP Compression in ASP.NET pages.&lt;/li&gt;
	&lt;div align="center" style="background-color: #F7F7F7;"&gt;&lt;b&gt;Note:&lt;/b&gt; &lt;em&gt;The Request Handler is now handed over the request.&lt;/em&gt;&lt;/div&gt;
&lt;li&gt;&lt;code&gt;PostRequestHandlerExecute&lt;/code&gt; - Occurs right after the request handler has been executed.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ReleaseRequestState&lt;/code&gt; - Occurs when the state (e.g., session state associated with the request) associated with the request is being released.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PostReleaseRequestState&lt;/code&gt; - Occurs when the state associated with the request has been released.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;UpdateRequestCache&lt;/code&gt; - Occurs when request handler has executed the request. This event provides opportunity to HTTP Modules that want to cache the response generated by this request so that subesquent requests can be handled directly from the cache.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PostUpdateRequestCache&lt;/code&gt; - Occurs when HTTP Modules that wanted to cache the response generated by this request have finished doing so.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;LogRequest&lt;/code&gt; - Occurs when ASP.NET is logging this request. This event is supported by IIS 7.0 in &lt;b&gt;integrated mode&lt;/b&gt; with .NET Framework 3.0 or above.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PostLogRequest&lt;/code&gt; - Occurs when ASP.NET has finished logging this request. Again, this event is only supported in IIS 7.0 in &lt;b&gt;integrated mode&lt;/b&gt; with .NET Framework 3.0 or above.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;EndRequest&lt;/code&gt; - Finally, this is the last event in the chain of events in web request handling pipeline.&lt;/li&gt;
&lt;/ol&gt;

&lt;div align="center" style="background-color: #F7F7F7;"&gt;&lt;b&gt;Note:&lt;/b&gt; Above events are associated with &lt;code&gt;HttpApplication&lt;/code&gt; object, the reference of which is provided to all HTTP Modules when they are initialized so that they can subscribe to the events of their interest.&lt;/div&gt;

&lt;p&gt;We will now learn what an HTTP Module looks like in the code and how it can subscribe to and handle these events.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Structure of an HTTP Module&lt;/b&gt;&lt;br /&gt;
An HTTP Module is an ordinary class that implements &lt;code&gt;IHttpModule&lt;/code&gt; interface.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;IHttpModule&lt;/b&gt;&lt;br /&gt;
It is defined in the &lt;code&gt;System.Web&lt;/code&gt; namespace. This interface has just two methods to be implemented as described below:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;Init(HttpApplication application)&lt;/code&gt; - This method is called by ASP.NET to &lt;em&gt;initialize&lt;/em&gt; the HTTP Module. In this method, the HTTP Module can use the supplied argument of type, &lt;code&gt;HttpApplication&lt;/code&gt;, to subscribe to events it wishes to handle.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Dispose()&lt;/code&gt; - This method is called by ASP.NET just before it wishes to &lt;em&gt;dispose&lt;/em&gt; the given &lt;em&gt;instance&lt;/em&gt; of an HTTP Module.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;b&gt;HttpApplication Events&lt;/b&gt;&lt;br /&gt;
The &lt;code&gt;HttpApplication&lt;/code&gt; object passed as the argument in the &lt;code&gt;Init()&lt;/code&gt; method of the &lt;code&gt;IHttpModule&lt;/code&gt; interface can be used by the HTTP Module to subscribe to events of its choice. The list of the events available to the HTTP Module has already been given above.&lt;/p&gt;

&lt;div align="center" style="background-color: #F7F7F7;"&gt;&lt;b&gt;Note:&lt;/b&gt; You should only handle the event(s) that is/are most appropriate for the task that you want to achieve with your HTTP Module.&lt;/div&gt;

&lt;p&gt;Now that you have seen &lt;code&gt;IHttpModule&lt;/code&gt; interface and are aware of the events that are made available to HTTP Modules, we will look at the code of an empty HTTP Module and later add some code to handle an event from the web request handling pipeline.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Creating your first HTTP Module&lt;/b&gt;&lt;br /&gt;
Following code shows how a class can implement the &lt;code&gt;IHttpModule&lt;/code&gt; interface:&lt;/p&gt;

&lt;pre&gt;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;

namespace Stardeveloper.Modules
{
	public class SampleModule : IHttpModule
	{
		public void Init(HttpApplication application)
		{
		}

		public void Dispose()
		{
		}
	}
}&lt;/pre&gt;

&lt;p&gt;That wasn't too much of a code, was it? A class with the name of &lt;code&gt;SampleModule&lt;/code&gt; declared in the &lt;code&gt;Stardeveloper.Modules&lt;/code&gt; namespace implements the &lt;code&gt;IHttpModule&lt;/code&gt; interface. An empty implementation of the methods is shown above.&lt;/p&gt;

&lt;p&gt;To handle events in the web request handling pipeline, it subscribes to them as follows:&lt;/p&gt;

&lt;pre&gt;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;

namespace Stardeveloper.Modules
{
	public class SampleModule : IHttpModule
	{
		public void Init(HttpApplication application)
		{
			application.PreRequestHandlerExecute +=
				new EventHandler(application_PreRequestHandlerExecute);
			application.PostRequestHandlerExecute +=
				new EventHandler(application_PostRequestHandlerExecute);
		}

		protected void application_PreRequestHandlerExecute(object sender,
			EventArgs e)
		{
			HttpApplication application = sender as HttpApplication;
			application.Response.Write(&amp;quot;Welcome!&amp;quot;);
		}
		
		protected void application_PostRequestHandlerExecute(object sender,
			EventArgs e)
		{
			HttpApplication application = sender as HttpApplication;
			application.Response.Write(&amp;quot;Bye!&amp;quot;);
		}

		public void Dispose()
		{
		}
	}
}&lt;/pre&gt;&lt;p&gt;Same class now uses C#'s syntax of subscribing to events to subscribe to two events; &lt;code&gt;PreRequestHandlerExecute&lt;/code&gt; and &lt;code&gt;PostRequestHandlerExecute&lt;/code&gt;. In the body of the event handlers, it casts the reference from the &lt;code&gt;sender&lt;/code&gt; object to &lt;code&gt;HttpApplication&lt;/code&gt; object and uses its &lt;code&gt;Response&lt;/code&gt; property (which is of type &lt;code&gt;HttpResponse&lt;/code&gt;) to write some text in the response being sent to the client browser.&lt;/p&gt;

&lt;p&gt;To install this module in your ASP.NET web application, place this code in &lt;code&gt;SampleModule.cs&lt;/code&gt; file and put it in the &lt;code&gt;/App_Code&lt;/code&gt; folder of your ASP.NET web application. Then edit your &lt;code&gt;web.config&lt;/code&gt; file to add following line within the &amp;quot;&lt;code&gt;httpModules&lt;/code&gt;&amp;quot; section:&lt;/p&gt;

&lt;pre&gt;
&amp;lt;configuration&amp;gt;
	&amp;lt;system.web&amp;gt;
		&amp;lt;httpModules&amp;gt;
			&amp;lt;add name=&amp;quot;SampleModule&amp;quot; type=&amp;quot;Stardeveloper.Modules.SampleModule&amp;quot;/&amp;gt;
		&amp;lt;/httpModules&amp;gt;
	&amp;lt;/system.web&amp;gt;
&amp;lt;/configuration&amp;gt;&lt;/pre&gt;

&lt;p&gt;Now, when you access any ASP.NET page within your ASP.NET web application, you will see all the text wrapped between &amp;quot;Welcome!&amp;quot; and &amp;quot;Bye!&amp;quot;.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Summary&lt;/b&gt;&lt;br /&gt;
In this tutorial, we were introduced with the concept of events in the web request handling pipeline. We also got a good idea of what HTTP Modules can do. We then looked at the &lt;code&gt;IHttpModule&lt;/code&gt; interface and &lt;code&gt;HttpApplication&lt;/code&gt; object. Finally, we created an empty HTTP Module, made it handle a couple of events from the web request handling pipeline, configure it in the &lt;code&gt;web.config&lt;/code&gt; file, and display some text to the user.&lt;/p&gt;

&lt;p&gt;In the next tutorial, we will look at a more real-World example of an HTTP Module in action.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.stardeveloper.com/~ff/StardevelopercomArticleHeadlines?a=gzdvaqfZZr4:b2zLk2uX0-E:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/StardevelopercomArticleHeadlines?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.stardeveloper.com/~ff/StardevelopercomArticleHeadlines?a=gzdvaqfZZr4:b2zLk2uX0-E:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/StardevelopercomArticleHeadlines?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/StardevelopercomArticleHeadlines/~4/gzdvaqfZZr4" height="1" width="1"/&gt;</description>
<guid isPermaLink="false"><![CDATA[http://www.stardeveloper.com/articles/display.html?article=2009071801&page=1]]></guid>
<author>Faisal Khan</author>
<pubDate>Sat, 18 Jul 2009 09:00:00 GMT</pubDate>
<atom:link href="http://feeds.stardeveloper.com/StardevelopercomArticleHeadlines" rel="self" type="application/rss+xml" /><feedburner:origLink>http://www.stardeveloper.com/articles/display.html?article=2009071801&amp;page=1</feedburner:origLink></item>
<item>
<title>Displaying Emails from Mailbox on Gmail using POP3 and ASP.NET</title>
<link>http://feeds.stardeveloper.com/~r/StardevelopercomArticleHeadlines/~3/XXDt3_os0mA/display.html</link>
<description>&lt;p&gt;&lt;b&gt;Introduction&lt;/b&gt;&lt;br /&gt;
In this tutorial, we will create the missing ASP.NET page, that was left in the previous tutorial (&lt;a href="http://www.stardeveloper.com/articles/display.html?article=2009070801&amp;page=1"&gt;Connecting to Mailbox on Gmail and Fetching List of Emails using POP3 and ASP.NET&lt;/a&gt;), that takes an individual email's sort number on the POP3 server to retrieve and display it to the user after properly decoding content-transfer-encodings like &lt;code&gt;base64&lt;/code&gt; and &lt;code&gt;quoted-printable&lt;/code&gt;. You will learn how to access individual message parts in MIME encoded emails including fetching and enlisting attachments.&lt;/p&gt;

&lt;div align="center" style="background-color: #F7F7F7;"&gt;&lt;b&gt;Note:&lt;/b&gt; It is mandatory that you read the previous tutorial (&lt;a href="http://www.stardeveloper.com/articles/display.html?article=2009070801&amp;page=1"&gt;Connecting to Mailbox on Gmail and Fetching List of Emails using POP3 and ASP.NET&lt;/a&gt;) to download and place the essential &lt;code&gt;Pop3.cs&lt;/code&gt; file in the &lt;code&gt;/App_Code&lt;/code&gt; folder of your ASP.NET web application. Without this code, you will not be able to connect and retrieve emails using POP3.&lt;/div&gt;

&lt;p&gt;In the previous tutorial, we limited ourselves to only listing the emails in our mailbox on Gmail. That in itself was quite a bit of a job since we had to develop all the baseline code that connects, sends commands, receives data, parses and instantiates objects. The classes that we created like &lt;code&gt;Pop3Client&lt;/code&gt;, &lt;code&gt;Email&lt;/code&gt;, and &lt;code&gt;MessagePart&lt;/code&gt; made the task a lot more easier for us. Only few lines of code were needed to retrieve the list of emails in the mailbox and display it on the ASP.NET page. We will build on that base in this tutorial.&lt;/p&gt;

&lt;div style="font-family: 'Georgia'; font-size: 10pt; padding: 1em; border: dotted 1px #111"&gt;If you are looking for a production ready, stable, easy to use ASP.NET Newsletter application, then look no further: &lt;strong&gt;Faisal Khan (the author of this tutorial) has created a great &lt;a href="http://www.stardeveloper.com/newsletter/"&gt;Newsletter Application&lt;/a&gt; for you to download and start using today.&lt;/strong&gt; It is easy to install, lets your users subscribe using a subscription form, provides a simple administration interface to create and send newsletters, handles the task of sending newsletters in the background using thread queues on the server, and lets users unsubscribe if they wish so.&lt;/div&gt;

&lt;p&gt;Following is the screen shot of the ASP.NET page that we developed in the previous tutorial:&lt;/p&gt;

&lt;div align="center"&gt;
&lt;img src="http://www.stardeveloper.com/images/articles/2009071001_pop3-listing-emails.gif" width="600" height="235" border="0" alt="Listing emails" /&gt;
&lt;/div&gt;

&lt;p&gt;If you followed previous tutorial and created &lt;code&gt;Pop3Client.aspx&lt;/code&gt; ASP.NET page that is listing the emails as shown in screen shot above, you'd have found out that the subject of the email is displayed as a link to &lt;code&gt;DisplayPop3Email.aspx&lt;/code&gt; ASP.NET page. That ASP.NET page is what we will create in this tutorial.&lt;/p&gt;

&lt;p&gt;Following screen shots shows &lt;code&gt;DisplayPop3Email.aspx&lt;/code&gt; ASP.NET page displaying a plain text email:&lt;/p&gt;

&lt;div align="center"&gt;
&lt;img src="http://www.stardeveloper.com/images/articles/2009071001_pop3-asp.net-plain-text-email.gif" width="600" height="252" border="0" alt="A plain text email" /&gt;
&lt;/div&gt;

&lt;p&gt;Following screen shot shows &lt;code&gt;DisplayPop3Email.aspx&lt;/code&gt; displaying an HTML email:&lt;/p&gt;

&lt;div align="center"&gt;
&lt;img src="http://www.stardeveloper.com/images/articles/2009071001_pop3-asp.net-html-email.gif" width="600" height="344" border="0" alt="An HTML email" /&gt;
&lt;/div&gt;

&lt;p&gt;Following screen shot shows &lt;code&gt;DisplayPop3Email.aspx&lt;/code&gt; listing attachments:&lt;/p&gt;

&lt;div align="center"&gt;
&lt;img src="http://www.stardeveloper.com/images/articles/2009071001_pop3-asp.net-listing-attachments.gif" width="600" height="322" border="0" alt="An Email with attachments" /&gt;
&lt;/div&gt;

&lt;p&gt;Now that you know what &lt;code&gt;DisplayPop3Email.aspx&lt;/code&gt; ASP.NET page that we will create in this tutorial will do, we will now go straight into its code.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;DisplayPop3Email.aspx&lt;/b&gt;&lt;br /&gt;
Open Notepad and copy following text in it. Then save it as &amp;quot;&lt;code&gt;DisplayPop3Email.aspx&lt;/code&gt;&amp;quot; in your ASP.NET web application where you saved &lt;code&gt;Pop3Client.aspx&lt;/code&gt; ASP.NET page from the previous tutorial:&lt;/p&gt;

&lt;pre&gt;
&amp;lt;%@ Page Language=&amp;quot;C#&amp;quot; %&amp;gt;

&amp;lt;%@ Import Namespace=&amp;quot;System.Collections.Generic&amp;quot; %&amp;gt;
&amp;lt;%@ Import Namespace=&amp;quot;Stardeveloper.Pop3&amp;quot; %&amp;gt;

&amp;lt;script runat=&amp;quot;server&amp;quot;&amp;gt;
	public const string Host = &amp;quot;pop.gmail.com&amp;quot;;
	public const int Port = 995;
	public const string Email = &amp;quot;youremail@gmail.com&amp;quot;;
	public const string Password = &amp;quot;yourpassword&amp;quot;;

	protected static Regex CharsetRegex =
		new Regex(&amp;quot;charset=\&amp;quot;?(?&amp;lt;charset&amp;gt;[^\\s\&amp;quot;]+)\&amp;quot;?&amp;quot;,
		RegexOptions.IgnoreCase | RegexOptions.Compiled);
	protected static Regex QuotedPrintableRegex =
		new Regex(&amp;quot;=(?&amp;lt;hexchars&amp;gt;[0-9a-fA-F]{2,2})&amp;quot;,
		RegexOptions.IgnoreCase | RegexOptions.Compiled);
	protected static Regex UrlRegex =
		new Regex(&amp;quot;(?&amp;lt;url&amp;gt;https?://[^\\s\&amp;quot;]+)&amp;quot;,
		RegexOptions.IgnoreCase | RegexOptions.Compiled);
	protected static Regex FilenameRegex =
		new Regex(&amp;quot;filename=\&amp;quot;?(?&amp;lt;filename&amp;gt;[^\\s\&amp;quot;]+)\&amp;quot;?&amp;quot;,
		RegexOptions.IgnoreCase| RegexOptions.Compiled);
	protected static Regex NameRegex =
		new Regex(&amp;quot;name=\&amp;quot;?(?&amp;lt;filename&amp;gt;[^\\s\&amp;quot;]+)\&amp;quot;?&amp;quot;,
		RegexOptions.IgnoreCase | RegexOptions.Compiled);

	protected void Page_Load(object source, EventArgs e)
	{
		/* Setting email id */
		int emailId = -1;

		if (Request.QueryString[&amp;quot;emailId&amp;quot;] == null)
		{
			Response.Redirect(&amp;quot;Pop3Client.aspx&amp;quot;);
			Response.Flush();
			Response.End();
		}
		else
			emailId = Convert.ToInt32(
				Request.QueryString[&amp;quot;emailId&amp;quot;]);

		/* Creating Pop3Client object and accessing email data */
		Email email = null;
		List&amp;lt;MessagePart&amp;gt; msgParts = null;

		using (Pop3Client client = new Pop3Client(Host, Port,
			Email, Password, true))
		{
			client.Connect();

			// Fetching email headers
			email = client.FetchEmail(emailId);
			// Fetching email body
			msgParts = client.FetchMessageParts(emailId);
		}

		if (email == null || msgParts == null)
		{
			Response.Redirect(&amp;quot;Pop3Client.aspx&amp;quot;);
			Response.Flush();
			Response.End();
		}

		/* Selecting a message part to display to the user */
		MessagePart preferredMsgPart = FindMessagePart(msgParts, &amp;quot;text/html&amp;quot;);

		if (preferredMsgPart == null)
			preferredMsgPart = FindMessagePart(msgParts, &amp;quot;text/plain&amp;quot;);
		else if (preferredMsgPart == null &amp;amp;&amp;amp; msgParts.Count &amp;gt; 0)
			preferredMsgPart = msgParts[0];

		string contentType, charset, contentTransferEncoding, body = null;

		if (preferredMsgPart != null)
		{
			contentType = preferredMsgPart.Headers[&amp;quot;Content-Type&amp;quot;];
			charset = &amp;quot;us-ascii&amp;quot;; // default charset
			contentTransferEncoding =
				preferredMsgPart.Headers[&amp;quot;Content-Transfer-Encoding&amp;quot;];

			Match m = CharsetRegex.Match(contentType);

			if (m.Success)
				charset = m.Groups[&amp;quot;charset&amp;quot;].Value;

			HeadersLiteral.Text = contentType != null ? &amp;quot;Content-Type: &amp;quot; +
				contentType + &amp;quot;&amp;lt;br /&amp;gt;&amp;quot; : string.Empty;
			HeadersLiteral.Text += contentTransferEncoding != null ?
				&amp;quot;Content-Transfer-Encoding: &amp;quot; +
				contentTransferEncoding : string.Empty;

			/* Decoding base64 and quoted-printable encoded messages */
			if (contentTransferEncoding != null)
			{
				if (contentTransferEncoding.ToLower() == &amp;quot;base64&amp;quot;)
					body = DecodeBase64String(charset,
						preferredMsgPart.MessageText);
				else if (contentTransferEncoding.ToLower() ==
						&amp;quot;quoted-printable&amp;quot;)
					body = DecodeQuotedPrintableString(
						preferredMsgPart.MessageText);
				else
					body = preferredMsgPart.MessageText;
			}
			else
				body = preferredMsgPart.MessageText;
		}

		/* Displaying information to the user */
		EmailIdLiteral.Text = Convert.ToString(emailId);
		DateLiteral.Text = email.UtcDateTime.ToString(); ;
		FromLiteral.Text = email.From;
		SubjectLiteral.Text = email.Subject;
		BodyLiteral.Text = preferredMsgPart != null ? 
			(preferredMsgPart.Headers[&amp;quot;Content-Type&amp;quot;]
				.IndexOf(&amp;quot;text/plain&amp;quot;) != -1 ?
			&amp;quot;&amp;lt;pre&amp;gt;&amp;quot; + FormatUrls(body) + &amp;quot;&amp;lt;/pre&amp;gt;&amp;quot; : body) : null;

		ListAttachments(msgParts);
	}&lt;/pre&gt;

&lt;p&gt;The code continues on the next page.&lt;/p&gt;&lt;p&gt;The code continues from the previous page.&lt;/p&gt;

&lt;pre&gt;
	protected Decoder GetDecoder(string charset)
	{
		Decoder decoder;

		switch (charset.ToLower())
		{
			case &amp;quot;utf-7&amp;quot;:
				decoder = Encoding.UTF7.GetDecoder();
				break;
			case &amp;quot;utf-8&amp;quot;:
				decoder = Encoding.UTF8.GetDecoder();
				break;
			case &amp;quot;us-ascii&amp;quot;:
				decoder = Encoding.ASCII.GetDecoder();
				break;
			case &amp;quot;iso-8859-1&amp;quot;:
				decoder = Encoding.ASCII.GetDecoder();
				break;
			default:
				decoder = Encoding.ASCII.GetDecoder();
				break;
		}

		return decoder;
	}

	protected string DecodeBase64String(string charset, string encodedString)
	{
		Decoder decoder = GetDecoder(charset);

		byte[] buffer = Convert.FromBase64String(encodedString);
		char[] chararr = new char[decoder.GetCharCount(buffer,
			0, buffer.Length)];

		decoder.GetChars(buffer, 0, buffer.Length, chararr, 0);

		return new string(chararr);
	}

	protected string DecodeQuotedPrintableString(string encodedString)
	{
		StringBuilder b = new StringBuilder();
		int startIndx = 0;

		MatchCollection matches = QuotedPrintableRegex.Matches(encodedString);

		for (int i = 0; i &amp;lt; matches.Count; i++)
		{
			Match m = matches[i];
			string hexchars = m.Groups[&amp;quot;hexchars&amp;quot;].Value;
			int charcode = Convert.ToInt32(hexchars, 16);
			char c = (char)charcode;

			if (m.Index &amp;gt; 0)
				b.Append(encodedString.Substring(startIndx,
					(m.Index - startIndx)));

			b.Append(c);

			startIndx = m.Index + 3;
		}
		
		if (startIndx &amp;lt; encodedString.Length)
			b.Append(encodedString.Substring(startIndx));

		return Regex.Replace(b.ToString(), &amp;quot;=\r\n&amp;quot;, &amp;quot;&amp;quot;);
	}

	protected void ListAttachments(List&amp;lt;MessagePart&amp;gt; msgParts)
	{
		bool attachmentsFound = false;
		StringBuilder b = new StringBuilder();
		b.Append(&amp;quot;&amp;lt;ol&amp;gt;&amp;quot;);

		foreach (MessagePart p in msgParts)
		{
			string contentType = p.Headers[&amp;quot;Content-Type&amp;quot;];
			string contentDisposition = p.Headers[&amp;quot;Content-Disposition&amp;quot;];

			Match m;

			if (contentDisposition != null)
			{
				m = FilenameRegex.Match(contentDisposition);

				if (m.Success)
				{
					attachmentsFound = true;
					b.Append(&amp;quot;&amp;lt;li&amp;gt;&amp;quot;).
						Append(m.Groups[&amp;quot;filename&amp;quot;].
							Value).Append(&amp;quot;&amp;lt;/li&amp;gt;&amp;quot;);
				}
			}
			else if (contentType != null)
			{
				m = NameRegex.Match(contentType);

				if (m.Success)
				{
					attachmentsFound = true;
					b.Append(&amp;quot;&amp;lt;li&amp;gt;&amp;quot;).
						Append(m.Groups[&amp;quot;filename&amp;quot;].
							Value).Append(&amp;quot;&amp;lt;/li&amp;gt;&amp;quot;);
				}
			}
		}
			
		b.Append(&amp;quot;&amp;lt;/ol&amp;gt;&amp;quot;);

		if (attachmentsFound)
			AttachmentsLiteral.Text = b.ToString();
		else
			AttachementsRow.Visible = false;
	}

	protected MessagePart FindMessagePart(List&amp;lt;MessagePart&amp;gt; msgParts,
		string contentType)
	{
		foreach (MessagePart p in msgParts)
			if (p.ContentType != null &amp;amp;&amp;amp;
					p.ContentType.IndexOf(contentType) != -1)
				return p;

		return null;
	}

	protected string FormatUrls(string plainText)
	{
		string replacementLink = &amp;quot;&amp;lt;a href=\&amp;quot;${url}\&amp;quot;&amp;gt;${url}&amp;lt;/a&amp;gt;&amp;quot;;

		return UrlRegex.Replace(plainText, replacementLink);
	}
&amp;lt;/script&amp;gt;

&amp;lt;!DOCTYPE html PUBLIC &amp;quot;-//W3C//DTD XHTML 1.0 Transitional//EN&amp;quot;
	&amp;quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&amp;quot;&amp;gt;

&amp;lt;html xmlns=&amp;quot;http://www.w3.org/1999/xhtml&amp;quot;&amp;gt;
&amp;lt;head runat=&amp;quot;server&amp;quot;&amp;gt;
    &amp;lt;title&amp;gt;&amp;lt;/title&amp;gt;
    &amp;lt;style type=&amp;quot;text/css&amp;quot;&amp;gt;
		.emails-table { width: 600px; border: solid 1px #444444; }
		.emails-table-header { font-family: &amp;quot;Trebuchet MS&amp;quot;; font-size: 9pt;
			background-color: #0099B9; font-weight: bold; color: white;
			text-align: center; border: solid 1px #444444; }
		.emails-table-header-cell { font-family: &amp;quot;Georgia&amp;quot;; font-size: 9pt;
			font-weight: bold; border: solid 1px #666666; padding: 6px; }
		.emails-table-cell { font-family: &amp;quot;Georgia&amp;quot;; font-size: 9pt;
			border: solid 1px #666666; padding: 6px; }
		.emails-table-footer { border: solid 1px #666666; padding: 3px;
			width: 50%; }
		.email-datetime { float: right; color: #666666; }
		
		a { font-family: &amp;quot;Lucida Sans Unicode&amp;quot;, &amp;quot;Trebuchet MS&amp;quot;; font-size: 9pt;
			color: #005B7F; }
		a:hover { color:red; }
		pre { font-family: &amp;quot;Georgia&amp;quot;; font-size: 9pt; }
    &amp;lt;/style&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
    &amp;lt;form id=&amp;quot;form1&amp;quot; runat=&amp;quot;server&amp;quot;&amp;gt;
    &amp;lt;asp:Literal ID=&amp;quot;DebugLiteral&amp;quot; runat=&amp;quot;server&amp;quot; /&amp;gt;
    
    &amp;lt;table class=&amp;quot;emails-table&amp;quot;&amp;gt;
    &amp;lt;tr&amp;gt;
		&amp;lt;td class=&amp;quot;emails-table-header&amp;quot; colspan=&amp;quot;2&amp;quot;&amp;gt;
		Email #&amp;lt;asp:Literal ID=&amp;quot;EmailIdLiteral&amp;quot; runat=&amp;quot;server&amp;quot; /&amp;gt;&amp;lt;/td&amp;gt;
    &amp;lt;/tr&amp;gt;
    &amp;lt;tr&amp;gt;
		&amp;lt;td class=&amp;quot;emails-table-header-cell&amp;quot;&amp;gt;Date &amp;amp;amp; Time&amp;lt;/td&amp;gt;
		&amp;lt;td class=&amp;quot;emails-table-cell&amp;quot;&amp;gt;
			&amp;lt;asp:Literal ID=&amp;quot;DateLiteral&amp;quot; runat=&amp;quot;server&amp;quot; /&amp;gt;&amp;lt;/td&amp;gt;
    &amp;lt;/tr&amp;gt;
    &amp;lt;tr&amp;gt;
		&amp;lt;td class=&amp;quot;emails-table-header-cell&amp;quot;&amp;gt;From&amp;lt;/td&amp;gt;
		&amp;lt;td class=&amp;quot;emails-table-cell&amp;quot;&amp;gt;
			&amp;lt;asp:Literal ID=&amp;quot;FromLiteral&amp;quot; runat=&amp;quot;server&amp;quot; /&amp;gt;&amp;lt;/td&amp;gt;
    &amp;lt;/tr&amp;gt;
    &amp;lt;tr&amp;gt;
		&amp;lt;td class=&amp;quot;emails-table-header-cell&amp;quot;&amp;gt;Subject&amp;lt;/td&amp;gt;
		&amp;lt;td class=&amp;quot;emails-table-cell&amp;quot;&amp;gt;
			&amp;lt;asp:Literal ID=&amp;quot;SubjectLiteral&amp;quot; runat=&amp;quot;server&amp;quot; /&amp;gt;&amp;lt;/td&amp;gt;
    &amp;lt;/tr&amp;gt;
    &amp;lt;tr id=&amp;quot;AttachementsRow&amp;quot; runat=&amp;quot;server&amp;quot;&amp;gt;
		&amp;lt;td class=&amp;quot;emails-table-header-cell&amp;quot;&amp;gt;Attachments&amp;lt;/td&amp;gt;
		&amp;lt;td class=&amp;quot;emails-table-cell&amp;quot;&amp;gt;
			&amp;lt;asp:Literal ID=&amp;quot;AttachmentsLiteral&amp;quot; runat=&amp;quot;server&amp;quot; /&amp;gt;&amp;lt;/td&amp;gt;
    &amp;lt;/tr&amp;gt;
     &amp;lt;tr&amp;gt;
		&amp;lt;td class=&amp;quot;emails-table-cell&amp;quot; colspan=&amp;quot;2&amp;quot;&amp;gt;
			&amp;lt;asp:Literal ID=&amp;quot;HeadersLiteral&amp;quot; runat=&amp;quot;server&amp;quot; /&amp;gt;&amp;lt;/td&amp;gt;
    &amp;lt;/tr&amp;gt;
    &amp;lt;tr&amp;gt;
		&amp;lt;td class=&amp;quot;emails-table-cell&amp;quot; colspan=&amp;quot;2&amp;quot;&amp;gt;
			&amp;lt;asp:Literal ID=&amp;quot;BodyLiteral&amp;quot; runat=&amp;quot;server&amp;quot; /&amp;gt;&amp;lt;/td&amp;gt;
    &amp;lt;/tr&amp;gt;
    &amp;lt;/table&amp;gt;
    &amp;lt;/form&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/pre&gt;

&lt;p&gt;&lt;b&gt;Explanation&lt;/b&gt;&lt;br /&gt;
We will now dissect the code, bit by bit.&lt;/p&gt;

&lt;p&gt;The first thing we do is to use a &lt;code&gt;Page&lt;/code&gt; level declaration to tell the ASP.NET compiler that all the server-side code encountered in this document should, by default, be assumed to be of the language, C#.&lt;/p&gt;

&lt;pre&gt;&amp;lt;%@ Page Language=&amp;quot;C#&amp;quot; %&amp;gt;&lt;/pre&gt;

&lt;p&gt;Next, we import the necessary namespaces.&lt;/p&gt;

&lt;div align="center" style="background-color: #F7F7F7;"&gt;&lt;b&gt;Note:&lt;/b&gt; We are importing the namespace &lt;code&gt;Stardeveloper.Pop3&lt;/code&gt; to make use of the code that we created in the previous tutorial (&lt;a href="http://www.stardeveloper.com/articles/display.html?article=2009070801&amp;page=1"&gt;Connecting to Mailbox on Gmail and Fetching List of Emails using POP3 and ASP.NET&lt;/a&gt;). This will make available classes like &lt;code&gt;Pop3Client&lt;/code&gt;, &lt;code&gt;Email&lt;/code&gt; and &lt;code&gt;MessagePart&lt;/code&gt; to us.&lt;/div&gt;

&lt;pre&gt;
&amp;lt;%@ Import Namespace=&amp;quot;System.Collections.Generic&amp;quot; %&amp;gt;
&amp;lt;%@ Import Namespace=&amp;quot;Stardeveloper.Pop3&amp;quot; %&amp;gt;&lt;/pre&gt;

&lt;p&gt;All the server-side code is encapsulated between &lt;code&gt;script&lt;/code&gt; tags.&lt;/p&gt;

&lt;pre&gt;
&amp;lt;script runat=&amp;quot;server&amp;quot;&amp;gt;
	...
&amp;lt;/script&amp;gt;&lt;/pre&gt;&lt;p&gt;The &lt;code&gt;host&lt;/code&gt;, &lt;code&gt;port&lt;/code&gt;, &lt;code&gt;email&lt;/code&gt;, and &lt;code&gt;password&lt;/code&gt; arguments required in the constructor of &lt;code&gt;Pop3Client&lt;/code&gt; class will be set using the following four constants.&lt;/p&gt;

&lt;pre&gt;
public const string Host = &amp;quot;pop.gmail.com&amp;quot;;
public const int Port = 995;
public const string Email = &amp;quot;youremail@gmail.com&amp;quot;;
public const string Password = &amp;quot;yourpassword&amp;quot;;&lt;/pre&gt;

&lt;p&gt;Regular expressions used in the code later have been created as &lt;code&gt;static&lt;/code&gt; objects. The &lt;code&gt;RegexOptions.Compiled&lt;/code&gt; bit is also set in the constructor of all the &lt;code&gt;Regex&lt;/code&gt; objects so that they are compiled the first time they are used and from there onwards, running these regular expressions will be super fast.&lt;/p&gt;

&lt;pre&gt;
protected static Regex CharsetRegex =
	new Regex(&amp;quot;charset=\&amp;quot;?(?&amp;lt;charset&amp;gt;[^\\s\&amp;quot;]+)\&amp;quot;?&amp;quot;,
	RegexOptions.IgnoreCase | RegexOptions.Compiled);
protected static Regex QuotedPrintableRegex =
	new Regex(&amp;quot;=(?&amp;lt;hexchars&amp;gt;[0-9a-fA-F]{2,2})&amp;quot;,
	RegexOptions.IgnoreCase | RegexOptions.Compiled);
protected static Regex UrlRegex =
	new Regex(&amp;quot;(?&amp;lt;url&amp;gt;https?://[^\\s\&amp;quot;]+)&amp;quot;,
	RegexOptions.IgnoreCase | RegexOptions.Compiled);
protected static Regex FilenameRegex =
	new Regex(&amp;quot;filename=\&amp;quot;?(?&amp;lt;filename&amp;gt;[^\\s\&amp;quot;]+)\&amp;quot;?&amp;quot;,
	RegexOptions.IgnoreCase| RegexOptions.Compiled);
protected static Regex NameRegex =
	new Regex(&amp;quot;name=\&amp;quot;?(?&amp;lt;filename&amp;gt;[^\\s\&amp;quot;]+)\&amp;quot;?&amp;quot;,
	RegexOptions.IgnoreCase | RegexOptions.Compiled);&lt;/pre&gt;

&lt;p&gt;Now we will dig into the &lt;code&gt;Page_Load()&lt;/code&gt; method which is called with every request our &lt;code&gt;DisplayPop3Email.aspx&lt;/code&gt; receives.&lt;/p&gt;

&lt;pre&gt;
protected void Page_Load(object source, EventArgs e)
{
	...
}&lt;/pre&gt;

&lt;p&gt;We retrieve the &lt;code&gt;emailId&lt;/code&gt; value from the querystring and save it in a variable of the same name.&lt;/p&gt;

&lt;div align="center" style="background-color: #F7F7F7;"&gt;&lt;b&gt;Note:&lt;/b&gt; &lt;code&gt;emailId&lt;/code&gt; is the sort number of the email in the list of emails on the POP3 server. You can determine the number of emails by sending the &lt;code&gt;STAT&lt;/code&gt; command. For instance, you have 324 emails in your POP3 server. In those 324 emails, the email #324 is the latest email that your mailbox has received and email #1 is oldest email among all your emails in your mailbox. This is how emails are sorted by the POP3 server. Now if you want to retrieve the email #324, you should call the &lt;code&gt;DisplayPop3Email.aspx&lt;/code&gt; ASP.NET page with the querystring value of the variable &lt;code&gt;emailId&lt;/code&gt; set to 324 i.e., &lt;code&gt;DisplayPop3Email.aspx?emailId=324&lt;/code&gt;. I hope this wasn't too difficult for you to understand.&lt;/div&gt;

&lt;pre&gt;
/* Setting email id */
int emailId = -1;

if (Request.QueryString[&amp;quot;emailId&amp;quot;] == null)
{
	Response.Redirect(&amp;quot;Pop3Client.aspx&amp;quot;);
	Response.Flush();
	Response.End();
}
else
	emailId = Convert.ToInt32(
		Request.QueryString[&amp;quot;emailId&amp;quot;]);&lt;/pre&gt;

&lt;p&gt;Once we have created the &lt;code&gt;Pop3Client&lt;/code&gt; object, we quickly call its &lt;code&gt;Connect()&lt;/code&gt; method to connect with the POP3 server. Once there, we call &lt;code&gt;FetchEmail()&lt;/code&gt; and &lt;code&gt;FetchMessageParts()&lt;/code&gt; methods to retrieve the full email, including all headers and its body.&lt;/p&gt;

&lt;pre&gt;
/* Creating Pop3Client object and accessing email data */
Email email = null;
List&amp;lt;MessagePart&amp;gt; msgParts = null;

using (Pop3Client client = new Pop3Client(Host, Port,
	Email, Password, true))
{
	client.Connect();

	// Fetching email headers
	email = client.FetchEmail(emailId);
	// Fetching email body
	msgParts = client.FetchMessageParts(emailId);
}&lt;/pre&gt;

&lt;p&gt;If the email's sort number was invalid e.g., the POP3 server has 324 emails and you accessed email #325, null references will be created by the code segment above. In which case we redirect the user to the ASP.NET page listing all the emails.&lt;/p&gt;

&lt;pre&gt;
if (email == null || msgParts == null)
{
	Response.Redirect(&amp;quot;Pop3Client.aspx&amp;quot;);
	Response.Flush();
	Response.End();
}&lt;/pre&gt;

&lt;p&gt;We then try to iterate through all the &lt;code&gt;MessagePart&lt;/code&gt; objects retrieved from the email and find the one most appropriate to display on the page. We begin by finding an HTML version of the email. If we cannot find it, we search for a plain text version of the email. If there is still no one found, we select the first &lt;code&gt;MessagePart&lt;/code&gt; object we encounter in the list.&lt;/p&gt;

&lt;pre&gt;
/* Selecting a message part to display to the user */
MessagePart preferredMsgPart = FindMessagePart(msgParts, &amp;quot;text/html&amp;quot;);

if (preferredMsgPart == null)
	preferredMsgPart = FindMessagePart(msgParts, &amp;quot;text/plain&amp;quot;);
else if (preferredMsgPart == null &amp;amp;&amp;amp; msgParts.Count &amp;gt; 0)
	preferredMsgPart = msgParts[0];&lt;/pre&gt;

&lt;p&gt;One we have the &lt;code&gt;MessagePart&lt;/code&gt; object we want to display on the page, we use its &lt;code&gt;content-type&lt;/code&gt; and &lt;code&gt;content-transfer-encoding&lt;/code&gt; headers to determine if the message body needs to be decoded first. If the message's body was encoded using &lt;code&gt;base64&lt;/code&gt; or &lt;code&gt;quoted-printable&lt;/code&gt; transfer encodings, we decode the content first and then display it to the user.&lt;/p&gt;

&lt;pre&gt;
string contentType, charset, contentTransferEncoding, body = null;

if (preferredMsgPart != null)
{
	contentType = preferredMsgPart.Headers[&amp;quot;Content-Type&amp;quot;];
	charset = &amp;quot;us-ascii&amp;quot;; // default charset
	contentTransferEncoding =
		preferredMsgPart.Headers[&amp;quot;Content-Transfer-Encoding&amp;quot;];

	Match m = CharsetRegex.Match(contentType);

	if (m.Success)
		charset = m.Groups[&amp;quot;charset&amp;quot;].Value;

	HeadersLiteral.Text = contentType != null ? &amp;quot;Content-Type: &amp;quot; +
		contentType + &amp;quot;&amp;lt;br /&amp;gt;&amp;quot; : string.Empty;
	HeadersLiteral.Text += contentTransferEncoding != null ?
		&amp;quot;Content-Transfer-Encoding: &amp;quot; +
		contentTransferEncoding : string.Empty;

	/* Decoding base64 and quoted-printable encoded messages */
	if (contentTransferEncoding != null)
	{
		if (contentTransferEncoding.ToLower() == &amp;quot;base64&amp;quot;)
			body = DecodeBase64String(charset,
				preferredMsgPart.MessageText);
		else if (contentTransferEncoding.ToLower() ==
				&amp;quot;quoted-printable&amp;quot;)
			body = DecodeQuotedPrintableString(
				preferredMsgPart.MessageText);
		else
			body = preferredMsgPart.MessageText;
	}
	else
		body = preferredMsgPart.MessageText;
}&lt;/pre&gt;

&lt;p&gt;We set a few literals with information from the email to display on the page.&lt;/p&gt;

&lt;pre&gt;
/* Displaying information to the user */
EmailIdLiteral.Text = Convert.ToString(emailId);
DateLiteral.Text = email.UtcDateTime.ToString(); ;
FromLiteral.Text = email.From;
SubjectLiteral.Text = email.Subject;
BodyLiteral.Text = preferredMsgPart != null ? 
	(preferredMsgPart.Headers[&amp;quot;Content-Type&amp;quot;]
		.IndexOf(&amp;quot;text/plain&amp;quot;) != -1 ?
	&amp;quot;&amp;lt;pre&amp;gt;&amp;quot; + FormatUrls(body) + &amp;quot;&amp;lt;/pre&amp;gt;&amp;quot; : body) : null;

ListAttachments(msgParts);&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;GetDecoder()&lt;/code&gt; returns the appropriate decoder to decode the message text depending on the &lt;code&gt;charset&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;
protected Decoder GetDecoder(string charset)
{
	Decoder decoder;

	switch (charset.ToLower())
	{
		case &amp;quot;utf-7&amp;quot;:
			decoder = Encoding.UTF7.GetDecoder();
			break;
		case &amp;quot;utf-8&amp;quot;:
			decoder = Encoding.UTF8.GetDecoder();
			break;
		case &amp;quot;us-ascii&amp;quot;:
			decoder = Encoding.ASCII.GetDecoder();
			break;
		case &amp;quot;iso-8859-1&amp;quot;:
			decoder = Encoding.ASCII.GetDecoder();
			break;
		default:
			decoder = Encoding.ASCII.GetDecoder();
			break;
	}

	return decoder;
}&lt;/pre&gt;&lt;p&gt;&lt;code&gt;DecodeBase64String()&lt;/code&gt; decodes a &lt;code&gt;base64&lt;/code&gt; encoded message and returns the decoded text.&lt;/p&gt;

&lt;div align="center" style="background-color: #F7F7F7;"&gt;&lt;b&gt;Note:&lt;/b&gt; Most of the &lt;code&gt;base64&lt;/code&gt; encodings that you will encounter in a MIME encoded email will be for binary attachments that have been &lt;code&gt;base64&lt;/code&gt; encoded so that they can be attached as text with an email. But when when I went about to view emails on my email account, I encountered normal plain text emails that were &lt;code&gt;base64&lt;/code&gt; encoded. So I had to write a &lt;code&gt;base64&lt;/code&gt; decoder to decode and properly present them on the ASP.NET page.&lt;/div&gt;

&lt;pre&gt;
protected string DecodeBase64String(string charset, string encodedString)
{
	Decoder decoder = GetDecoder(charset);

	byte[] buffer = Convert.FromBase64String(encodedString);
	char[] chararr = new char[decoder.GetCharCount(buffer,
		0, buffer.Length)];

	decoder.GetChars(buffer, 0, buffer.Length, chararr, 0);

	return new string(chararr);
}&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;DecodeQuotedPrintableString()&lt;/code&gt; method decodes a message whose body has been encoded with &lt;code&gt;quoted-printable&lt;/code&gt; encoding.&lt;/p&gt;

&lt;pre&gt;
protected string DecodeQuotedPrintableString(string encodedString)
{
	StringBuilder b = new StringBuilder();
	int startIndx = 0;

	MatchCollection matches = QuotedPrintableRegex.Matches(encodedString);

	for (int i = 0; i &amp;lt; matches.Count; i++)
	{
		Match m = matches[i];
		string hexchars = m.Groups[&amp;quot;hexchars&amp;quot;].Value;
		int charcode = Convert.ToInt32(hexchars, 16);
		char c = (char)charcode;

		if (m.Index &amp;gt; 0)
			b.Append(encodedString.Substring(startIndx,
				(m.Index - startIndx)));

		b.Append(c);

		startIndx = m.Index + 3;
	}
	
	if (startIndx &amp;lt; encodedString.Length)
		b.Append(encodedString.Substring(startIndx));

	return Regex.Replace(b.ToString(), &amp;quot;=\r\n&amp;quot;, &amp;quot;&amp;quot;);
}&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;ListAttachments()&lt;/code&gt; method scans all the &lt;code&gt;MessagePart&lt;/code&gt; objects to determine which of these is an attachment. It then displays the list of attachments on the page.&lt;/p&gt;

&lt;pre&gt;
protected void ListAttachments(List&amp;lt;MessagePart&amp;gt; msgParts)
{
	bool attachmentsFound = false;
	StringBuilder b = new StringBuilder();
	b.Append(&amp;quot;&amp;lt;ol&amp;gt;&amp;quot;);

	foreach (MessagePart p in msgParts)
	{
		string contentType = p.Headers[&amp;quot;Content-Type&amp;quot;];
		string contentDisposition = p.Headers[&amp;quot;Content-Disposition&amp;quot;];

		Match m;

		if (contentDisposition != null)
		{
			m = FilenameRegex.Match(contentDisposition);

			if (m.Success)
			{
				attachmentsFound = true;
				b.Append(&amp;quot;&amp;lt;li&amp;gt;&amp;quot;).
					Append(m.Groups[&amp;quot;filename&amp;quot;].
						Value).Append(&amp;quot;&amp;lt;/li&amp;gt;&amp;quot;);
			}
		}
		else if (contentType != null)
		{
			m = NameRegex.Match(contentType);

			if (m.Success)
			{
				attachmentsFound = true;
				b.Append(&amp;quot;&amp;lt;li&amp;gt;&amp;quot;).
					Append(m.Groups[&amp;quot;filename&amp;quot;].
						Value).Append(&amp;quot;&amp;lt;/li&amp;gt;&amp;quot;);
			}
		}
	}
		
	b.Append(&amp;quot;&amp;lt;/ol&amp;gt;&amp;quot;);

	if (attachmentsFound)
		AttachmentsLiteral.Text = b.ToString();
	else
		AttachementsRow.Visible = false;
}&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;FindMessagePart()&lt;/code&gt; scans all the &lt;code&gt;MessagePart&lt;/code&gt; objects to find the one whose &lt;code&gt;content-type&lt;/code&gt; matches the &lt;code&gt;contentType&lt;/code&gt; argument.&lt;/p&gt;

&lt;pre&gt;
protected MessagePart FindMessagePart(List&amp;lt;MessagePart&amp;gt; msgParts,
	string contentType)
{
	foreach (MessagePart p in msgParts)
		if (p.ContentType != null &amp;amp;&amp;amp;
				p.ContentType.IndexOf(contentType) != -1)
			return p;

	return null;
}&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;FormatUrls()&lt;/code&gt; formats URL strings for display on the page.&lt;/p&gt;

&lt;pre&gt;
protected string FormatUrls(string plainText)
{
	string replacementLink = &amp;quot;&amp;lt;a href=\&amp;quot;${url}\&amp;quot;&amp;gt;${url}&amp;lt;/a&amp;gt;&amp;quot;;

	return UrlRegex.Replace(plainText, replacementLink);
}&lt;/pre&gt;

&lt;p&gt;Now that we have looked at the code, we will run this ASP.NET page.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Running DisplayPop3Email.aspx&lt;/b&gt;&lt;br /&gt;
I placed &lt;code&gt;Pop3.cs&lt;/code&gt; in the &lt;code&gt;/App_Code&lt;/code&gt; folder, &lt;code&gt;Pop3Client.aspx&lt;/code&gt; and &lt;code&gt;DisplayPop3Email.aspx&lt;/code&gt; in the root folder (&lt;code&gt;/&lt;/code&gt;). Then I started the ASP.NET web server and accessed &lt;code&gt;Pop3Client.aspx&lt;/code&gt; in the browser. From the emails' list that appeared, I clicked one email's subject and this brought me to the &lt;code&gt;DisplayPop3Email.aspx&lt;/code&gt; ASP.NET page that we just created. Following screen shot shows the result of this request:&lt;/p&gt;

&lt;div align="center"&gt;
&lt;img src="http://www.stardeveloper.com/images/articles/2009071001_pop3-listing-emails.gif" width="600" height="235" border="0" alt="Listing emails" /&gt;
&lt;/div&gt;

&lt;p&gt;&lt;b&gt;Summary&lt;/b&gt;&lt;br /&gt;
In this tutorial, we created an ASP.NET page that takes an email's sort number on the POP3 server and connects to, retrieves, and displays that email on the page. This ASP.NET page was the missing page that was left in the previous tutorial (&lt;a href="http://www.stardeveloper.com/articles/display.html?article=2009070801&amp;page=1"&gt;Connecting to Mailbox on Gmail and Fetching List of Emails using POP3 and ASP.NET&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;I hope you can expand and modify the source code of this application to suit the needs of your application or if you are a beginner, learn the network programming aspects of it.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.stardeveloper.com/~ff/StardevelopercomArticleHeadlines?a=XXDt3_os0mA:p5a1Nz9GIZU:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/StardevelopercomArticleHeadlines?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.stardeveloper.com/~ff/StardevelopercomArticleHeadlines?a=XXDt3_os0mA:p5a1Nz9GIZU:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/StardevelopercomArticleHeadlines?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/StardevelopercomArticleHeadlines/~4/XXDt3_os0mA" height="1" width="1"/&gt;</description>
<guid isPermaLink="false"><![CDATA[http://www.stardeveloper.com/articles/display.html?article=2009071001&page=1]]></guid>
<author>Faisal Khan</author>
<pubDate>Fri, 10 Jul 2009 05:52:00 GMT</pubDate>
<atom:link href="http://feeds.stardeveloper.com/StardevelopercomArticleHeadlines" rel="self" type="application/rss+xml" /><feedburner:origLink>http://www.stardeveloper.com/articles/display.html?article=2009071001&amp;page=1</feedburner:origLink></item>
<item>
<title>Connecting to Mailbox on Gmail and Fetching List of Emails using POP3 and ASP.NET</title>
<link>http://feeds.stardeveloper.com/~r/StardevelopercomArticleHeadlines/~3/ZHb7g3uF9Sk/display.html</link>
<description>&lt;p&gt;&lt;b&gt;Introduction&lt;/b&gt;&lt;br /&gt;
In this tutorial, we will learn about &lt;em&gt;Post Office Protocol (POP3)&lt;/em&gt;. It is a protocol (a set of commands) used by an email client to connect to and retrieve email(s) from the mailbox on the remote server. We will develop the code that connects to the POP3 server and sends commands to retrieve the list of emails on the server, and then later, using an ASP.NET page, displays the list to the user. &lt;em&gt;To demonstrate the code, we will be connecting to Gmail's POP3 server using SSL (Secure Sockets Layer)&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;To connect to your own POP3 mail server, you can either use the secure connection (SSL) if your mail server supports it or connect in unsecure mode. The code is simple to understand and by looking at it you will learn a lot about how network programming is done in the .NET environment.&lt;/p&gt;

&lt;div align="center" style="background-color: #F7F7F7;"&gt;&lt;b&gt;Note:&lt;/b&gt; In this tutorial, we will limit ourselves to retrieving and displaying a list of emails from user's mailbox which the user can browse through using &amp;apos;Previous Page&amp;apos; and &amp;apos;Next Page&amp;apos; links. In the next tutorial (&lt;a href="http://www.stardeveloper.com/articles/display.html?article=2009071001&amp;page=1"&gt;Displaying Emails from Mailbox on Gmail using POP3 and ASP.NET&lt;/a&gt;), we will learn how to retrieve and view an individual email.&lt;/div&gt;

&lt;p&gt;Following screen shot shows an ASP.NET page listing emails in my Gmail mailbox:&lt;/p&gt;

&lt;div align="center"&gt;
&lt;img src="http://www.stardeveloper.com/images/articles/2009071001_pop3-listing-emails.gif" width="600" height="235" border="0" alt="Connecting to mailbox on Gmail using POP3 and displaying list of emails" /&gt;
&lt;/div&gt;

&lt;div style="font-family: 'Georgia'; font-size: 10pt; padding: 1em; margin-top: 20px; border: dotted 1px #111"&gt;If you are looking for a production ready, stable, easy to use ASP.NET Newsletter application, then look no further: &lt;strong&gt;Faisal Khan (the author of this tutorial) has created a great &lt;a href="http://www.stardeveloper.com/newsletter/"&gt;Newsletter Application&lt;/a&gt; for you to download and start using today.&lt;/strong&gt; It is easy to install, lets your users subscribe using a subscription form, provides a simple administration interface to create and send newsletters, handles the task of sending newsletters in the background using thread queues on the server, and lets users unsubscribe if they wish so.&lt;/div&gt;

&lt;p&gt;&lt;b&gt;Basic POP3 Commands&lt;/b&gt;&lt;br /&gt;
Following is a list of commonly used POP3 commands:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;USER&lt;/code&gt; - Takes one argument i.e., the email address of the user trying to connect to his/her mailbox. Example usage:
&lt;pre&gt;
USER youremail@xyz.com&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PASS&lt;/code&gt; - Takes one argument i.e., the password of the user. Example usage:
&lt;pre&gt;
PASS yourpassword&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;STAT&lt;/code&gt; - Returns the number of emails in the mailbox and the number of bytes all the emails are taking on the server. Example usage:
&lt;pre&gt;
STAT&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;TOP&lt;/code&gt; - Takes two arguments i.e., the sort number of the email on the server and the number of lines of text to retrieve from the body of the email. Example usage:
&lt;pre&gt;
TOP 1 10&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;RETR&lt;/code&gt; - Takes one argument i.e., the sort number of the email on the server and returns all the headers and lines from the body of the email. Example usage:
&lt;pre&gt;
RETR 1&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DELE&lt;/code&gt; - Takes one argument i.e., the sort number of the email on the server and deletes it. Example usage:
&lt;pre&gt;
DELE 1&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;RSET&lt;/code&gt; - Resets any &lt;code&gt;DELE&lt;/code&gt; commands given above. The emails marked to be deleted by &lt;code&gt;DELE&lt;/code&gt; command are unmarked. Example usage:
&lt;pre&gt;
RSET&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;QUIT&lt;/code&gt; - Closes the user session with the server. Example usage:
&lt;pre&gt;
QUIT&lt;/pre&gt;

&lt;div align="center" style="background-color: #F7F7F7;"&gt;&lt;b&gt;Note:&lt;/b&gt; In the code that we will develop, we will not close the session with the remote server using &lt;code&gt;QUIT&lt;/code&gt; command. Because if we have issued &lt;code&gt;RETR&lt;/code&gt; command to retrieve any emails from the POP3 server, issuing &lt;code&gt;QUIT&lt;/code&gt; commands gives the wrong impression to the server that those emails have been downloaded safely on our system so the server can remove them from its list. Since we do not want to inadvertently remove or delete any emails from the POP3 server, we will not issue &lt;code&gt;QUIT&lt;/code&gt; command and simply close the connection.&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;b&gt;Developing the Code&lt;/b&gt;&lt;br /&gt;
In this tutorial, we will develop C# classes that encapsulate all the code that is necessary to connect to and retrieve emails from Gmail's mailbox. We will place these classes in &amp;quot;&lt;code&gt;Pop3.cs&lt;/code&gt;&amp;quot; C# source file. These classes will provide an easy to use interface to access the mailbox. An ASP.NET page with the name of &amp;quot;&lt;code&gt;Pop3Client.aspx&lt;/code&gt;&amp;quot; will use these classes to list emails in the mailbox.&lt;/p&gt;

&lt;p&gt;Files that we will develop in this tutorial:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;Pop3.cs&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Pop3Client.aspx&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;b&gt;i. Pop3.cs&lt;/b&gt;&lt;br /&gt;
All right guys, open Notepad and copy following code in it. Then save this new document as &lt;code&gt;Pop3.cs&lt;/code&gt; in the &lt;code&gt;/App_Code&lt;/code&gt; folder of your ASP.NET web application:&lt;/p&gt;

&lt;pre&gt;
/* Author: Faisal Khan */
/* &amp;copy; Stardeveloper.com */

using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Security;
using System.Net.Sockets;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using System.Xml;

namespace Stardeveloper.Pop3
{
  public class Pop3Client : IDisposable
  {
    public string Host { get; protected set; }
    public int Port { get; protected set; }
    public string Email { get; protected set; }
    public string Password { get; protected set; }
    public bool IsSecure { get; protected set; }

    public TcpClient Client { get; protected set; }
    public Stream ClientStream { get; protected set; }

    public StreamWriter Writer { get; protected set; }
    public StreamReader Reader { get; protected set; }

    private bool disposed = false;

    public Pop3Client(string host, int port, string email,
      string password)
      : this(host, port, email, password, false)
    {
    }

    public Pop3Client(string host, int port, string email,
      string password, bool secure)
    {
      Host = host;
      Port = port;
      Email = email;
      Password = password;
      IsSecure = secure;
    }

    public void Connect()
    {
      if (Client == null)
        Client = new TcpClient();

      if (!Client.Connected)
        Client.Connect(Host, Port);

      if (IsSecure)
      {
        SslStream secureStream =
          new SslStream(Client.GetStream());
        secureStream.AuthenticateAsClient(Host);

        ClientStream = secureStream;
        secureStream = null;
      }
      else
        ClientStream = Client.GetStream();

      Writer = new StreamWriter(ClientStream);
      Reader = new StreamReader(ClientStream);

      ReadLine();
      Login();
    }

    public int GetEmailCount()
    {
      int count = 0;
      string response = SendCommand(&amp;quot;STAT&amp;quot;);

      if (IsResponseOk(response))
      {
        string[] arr = response.Substring(4).Split(&amp;apos; &amp;apos;);
        count = Convert.ToInt32(arr[0]);
      }
      else
        count = -1;

      return count;
    }

    public Email FetchEmail(int emailId)
    {
      if (IsResponseOk(SendCommand(&amp;quot;TOP &amp;quot; + emailId + &amp;quot; 0&amp;quot;)))
        return new Email(ReadLines());
      else
        return null;
    }

    public List&amp;lt;Email&amp;gt; FetchEmailList(int start, int count)
    {
      List&amp;lt;Email&amp;gt; emails = new List&amp;lt;Email&amp;gt;(count);

      for (int i = start; i &amp;lt; (start + count); i++)
      {
        Email email = FetchEmail(i);

        if (email != null)
          emails.Add(email);
      }

      return emails;
    }

    public List&amp;lt;MessagePart&amp;gt; FetchMessageParts(int emailId)
    {
      if (IsResponseOk(SendCommand(&amp;quot;RETR &amp;quot; + emailId)))
        return Util.ParseMessageParts(ReadLines());

      return null;
    }&lt;/pre&gt;

&lt;p&gt;The code continues on the next page.&lt;/p&gt;&lt;p&gt;The code is continuing from the previous page.&lt;/p&gt;

&lt;pre&gt;
public List&amp;lt;MessagePart&amp;gt; FetchMessageParts(int emailId)
    {
      if (IsResponseOk(SendCommand(&amp;quot;RETR &amp;quot; + emailId)))
        return Util.ParseMessageParts(ReadLines());

      return null;
    }

    public void Close()
    {
      if (Client != null)
      {
        if (Client.Connected)
          Logout();

        Client.Close();
        Client = null;
      }

      if (ClientStream != null)
      {
        ClientStream.Close();
        ClientStream = null;
      }

      if (Writer != null)
      {
        Writer.Close();
        Writer = null;
      }

      if (Reader != null)
      {
        Reader.Close();
        Reader = null;
      }

      disposed = true;
    }

    public void Dispose()
    {
      if (!disposed)
        Close();
    }

    protected void Login()
    {
      if (!IsResponseOk(SendCommand(&amp;quot;USER &amp;quot; + Email)) ||
        !IsResponseOk(SendCommand(&amp;quot;PASS &amp;quot; + Password)))
        throw new Exception(&amp;quot;User/password not accepted&amp;quot;);
    }

    protected void Logout()
    {
      SendCommand(&amp;quot;RSET&amp;quot;);
      //SendCommand(&amp;quot;QUIT&amp;quot;);
    }

    protected string SendCommand(string cmdtext)
    {
      Writer.WriteLine(cmdtext);
      Writer.Flush();

      return ReadLine();
    }

    protected string ReadLine()
    {
      return Reader.ReadLine() + &amp;quot;\r\n&amp;quot;;
    }

    protected string ReadLines()
    {
      StringBuilder b = new StringBuilder();

      while (true)
      {
        string temp = ReadLine();

        if (temp == &amp;quot;.\r\n&amp;quot; || temp.IndexOf(&amp;quot;-ERR&amp;quot;) != -1)
          break;

        b.Append(temp);
      }

      return b.ToString();
    }

    protected static bool IsResponseOk(string response)
    {
      if (response.StartsWith(&amp;quot;+OK&amp;quot;))
        return true;
      if (response.StartsWith(&amp;quot;-ERR&amp;quot;))
        return false;

      throw new Exception(&amp;quot;Cannot understand server response: &amp;quot; +
        response);
    }
  }

  public class Email
  {
    public NameValueCollection Headers { get; protected set; }

    public string ContentType { get; protected set; }
    public DateTime UtcDateTime { get; protected set; }
    public string From { get; protected set; }
    public string To { get; protected set; }
    public string Subject { get; protected set; }

    public Email(string emailText)
    {
      Headers = Util.ParseHeaders(emailText);

      ContentType = Headers[&amp;quot;Content-Type&amp;quot;];
      From = Headers[&amp;quot;From&amp;quot;];
      To = Headers[&amp;quot;To&amp;quot;];
      Subject = Headers[&amp;quot;Subject&amp;quot;];

      if (Headers[&amp;quot;Date&amp;quot;] != null)
        try
        {
        UtcDateTime =
          Util.ConvertStrToUtcDateTime(Headers[&amp;quot;Date&amp;quot;]);
        }
        catch (FormatException)
        {
          UtcDateTime = DateTime.MinValue;
        }
      else
        UtcDateTime = DateTime.MinValue;
    }
  }

  public class MessagePart
  {
    public NameValueCollection Headers { get; protected set; }

    public string ContentType { get; protected set; }
    public string MessageText { get; protected set; }

    public MessagePart(NameValueCollection headers, string messageText)
    {
      Headers = headers;
      ContentType = Headers[&amp;quot;Content-Type&amp;quot;];
      MessageText = messageText;
    }
  }

  public class Util
  {
    protected static Regex BoundaryRegex =
      new Regex(&amp;quot;Content-Type: multipart(?:/\\S+;)&amp;quot; +
      &amp;quot;\\s+[^\r\n]*boundary=\&amp;quot;?(?&amp;lt;boundary&amp;gt;&amp;quot; +
      &amp;quot;[^\&amp;quot;\r\n]+)\&amp;quot;?\r\n&amp;quot;, RegexOptions.IgnoreCase |
      RegexOptions.Compiled);
    protected static Regex UtcDateTimeRegex = new Regex(
      @&amp;quot;^(?:\w+,\s+)?(?&amp;lt;day&amp;gt;\d+)\s+(?&amp;lt;month&amp;gt;\w+)\s+(?&amp;lt;year&amp;gt;\d+)\s+(?&amp;lt;hour&amp;gt;\d{1,2})&amp;quot; +
      @&amp;quot;:(?&amp;lt;minute&amp;gt;\d{1,2}):(?&amp;lt;second&amp;gt;\d{1,2})\s+(?&amp;lt;offsetsign&amp;gt;\-|\+)(?&amp;lt;offsethours&amp;gt;&amp;quot; +
      @&amp;quot;\d{2,2})(?&amp;lt;offsetminutes&amp;gt;\d{2,2})(?:.*)$&amp;quot;,
      RegexOptions.IgnoreCase | RegexOptions.Compiled);

    public static NameValueCollection ParseHeaders(string headerText)
    {
      NameValueCollection headers = new NameValueCollection();
      StringReader reader = new StringReader(headerText);

      string line;
      string headerName = null, headerValue;
      int colonIndx;

      while ((line = reader.ReadLine()) != null)
      {
        if (line == &amp;quot;&amp;quot;)
          break;

        if (Char.IsLetterOrDigit(line[0]) &amp;amp;&amp;amp; (colonIndx = line.IndexOf(&amp;apos;:&amp;apos;)) != -1)
        {
          headerName = line.Substring(0, colonIndx);
          headerValue = line.Substring(colonIndx + 1).Trim();

          headers.Add(headerName, headerValue);
        }
        else if (headerName != null)
          headers[headerName] += &amp;quot; &amp;quot; + line.Trim();
        else
          throw new FormatException(&amp;quot;Could not parse headers&amp;quot;);
      }

      return headers;
    }

    public static List&amp;lt;MessagePart&amp;gt; ParseMessageParts(string emailText)
    {
      List&amp;lt;MessagePart&amp;gt; messageParts = new List&amp;lt;MessagePart&amp;gt;();
      int newLinesIndx = emailText.IndexOf(&amp;quot;\r\n\r\n&amp;quot;);

      Match m = BoundaryRegex.Match(emailText);

      if (m.Index &amp;lt; emailText.IndexOf(&amp;quot;\r\n\r\n&amp;quot;) &amp;amp;&amp;amp; m.Success)
      {
        string boundary = m.Groups[&amp;quot;boundary&amp;quot;].Value;
        string startingBoundary = &amp;quot;\r\n--&amp;quot; + boundary;

        int startingBoundaryIndx = -1;

        while (true)
        {
          if (startingBoundaryIndx == -1)
            startingBoundaryIndx = emailText.IndexOf(startingBoundary);

          if (startingBoundaryIndx != -1)
          {
            int nextBoundaryIndx = emailText.IndexOf(startingBoundary,
              startingBoundaryIndx + startingBoundary.Length);

            if (nextBoundaryIndx != -1 &amp;amp;&amp;amp; nextBoundaryIndx != startingBoundaryIndx)
            {
              string multipartMsg = emailText.Substring(startingBoundaryIndx +
                startingBoundary.Length,
                (nextBoundaryIndx - startingBoundaryIndx - startingBoundary.Length));

              int headersIndx = multipartMsg.IndexOf(&amp;quot;\r\n\r\n&amp;quot;);

              if (headersIndx == -1)
                throw new FormatException(&amp;quot;Incompatible multipart message format&amp;quot;);

              string bodyText = multipartMsg.Substring(headersIndx).Trim();

              NameValueCollection headers = Util.ParseHeaders(multipartMsg.Trim());
              messageParts.Add(new MessagePart(headers, bodyText));
            }
            else
              break;

            startingBoundaryIndx = nextBoundaryIndx;
          }
          else
            break;
        }

        if (newLinesIndx != -1)
        {
          string emailBodyText = emailText.Substring(newLinesIndx + 1);
        }
      }
      else
      {
        int headersIndx = emailText.IndexOf(&amp;quot;\r\n\r\n&amp;quot;);

        if (headersIndx == -1)
          throw new FormatException(&amp;quot;Incompatible multipart message format&amp;quot;);

        string bodyText = emailText.Substring(headersIndx).Trim();

        NameValueCollection headers = Util.ParseHeaders(emailText);
        messageParts.Add(new MessagePart(headers, bodyText));
      }

      return messageParts;
    }&lt;/pre&gt;

&lt;p&gt;The code continues on the next page.&lt;/p&gt;&lt;p&gt;The code is continuing from the previous page.&lt;/p&gt;

&lt;pre&gt;
public static DateTime ConvertStrToUtcDateTime(string str)
    {
      Match m = UtcDateTimeRegex.Match(str);

      int day, month, year, hour, min, sec;

      if (m.Success)
      {
        day = Convert.ToInt32(m.Groups[&amp;quot;day&amp;quot;].Value);
        year = Convert.ToInt32(m.Groups[&amp;quot;year&amp;quot;].Value);
        hour = Convert.ToInt32(m.Groups[&amp;quot;hour&amp;quot;].Value);
        min = Convert.ToInt32(m.Groups[&amp;quot;minute&amp;quot;].Value);
        sec = Convert.ToInt32(m.Groups[&amp;quot;second&amp;quot;].Value);

        switch (m.Groups[&amp;quot;month&amp;quot;].Value)
        {
          case &amp;quot;Jan&amp;quot;:
            month = 1;
            break;
          case &amp;quot;Feb&amp;quot;:
            month = 2;
            break;
          case &amp;quot;Mar&amp;quot;:
            month = 3;
            break;
          case &amp;quot;Apr&amp;quot;:
            month = 4;
            break;
          case &amp;quot;May&amp;quot;:
            month = 5;
            break;
          case &amp;quot;Jun&amp;quot;:
            month = 6;
            break;
          case &amp;quot;Jul&amp;quot;:
            month = 7;
            break;
          case &amp;quot;Aug&amp;quot;:
            month = 8;
            break;
          case &amp;quot;Sep&amp;quot;:
            month = 9;
            break;
          case &amp;quot;Oct&amp;quot;:
            month = 10;
            break;
          case &amp;quot;Nov&amp;quot;:
            month = 11;
            break;
          case &amp;quot;Dec&amp;quot;:
            month = 12;
            break;
          default:
            throw new FormatException(&amp;quot;Unknown month.&amp;quot;);
        }

        string offsetSign = m.Groups[&amp;quot;offsetsign&amp;quot;].Value;
        int offsetHours = Convert.ToInt32(m.Groups[&amp;quot;offsethours&amp;quot;].Value);
        int offsetMinutes = Convert.ToInt32(m.Groups[&amp;quot;offsetminutes&amp;quot;].Value);

        DateTime dt = new DateTime(year, month, day, hour, min, sec);

        if (offsetSign == &amp;quot;+&amp;quot;)
        {
          dt.AddHours(offsetHours);
          dt.AddMinutes(offsetMinutes);
        }
        else if (offsetSign == &amp;quot;-&amp;quot;)
        {
          dt.AddHours(-offsetHours);
          dt.AddMinutes(-offsetMinutes);
        }

        return dt;
      }

      throw new FormatException(&amp;quot;Incompatible date/time string format&amp;quot;);
    }
  }
}&lt;/pre&gt;

&lt;p&gt;&lt;b&gt;Explanation&lt;/b&gt;&lt;br /&gt;
&lt;code&gt;Pop3.cs&lt;/code&gt; defines &lt;code&gt;Stardeveloper.Pop3&lt;/code&gt; namespace, which contains following 4 classes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;Pop3Client&lt;/code&gt; - This class uses classes in the &lt;code&gt;System.Net&lt;/code&gt; and sub-namespaces to connect with the Pop3 server and send commands. It retrieves the data, and uses the &lt;code&gt;Util&lt;/code&gt; class to create &lt;code&gt;Email&lt;/code&gt; and &lt;code&gt;MessagePart&lt;/code&gt; objects from the received data.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Email&lt;/code&gt; - It represents an Email message on the server. It provides you access to the &amp;quot;&lt;em&gt;From&lt;/em&gt;&amp;quot;, &amp;quot;&lt;em&gt;To&lt;/em&gt;&amp;quot;, &amp;quot;&lt;em&gt;Subject&lt;/em&gt;&amp;quot;, &amp;quot;&lt;em&gt;Date&lt;/em&gt;&amp;quot; and &amp;quot;&lt;em&gt;Content-Type&lt;/em&gt;&amp;quot; headers. It does not let you access the body of the email. The body of the email is represented by an array of &lt;code&gt;MessagePart&lt;/code&gt; objects which are retrieved separately by calling &lt;code&gt;Pop3Client.FetchMessageParts()&lt;/code&gt; method.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;MessagePart&lt;/code&gt; - It represents a part of the body of the email. Since most of the emails are MIME encoded, which means that there can be more than one type (text/plain, text/html, etc.) of message part, and that there can be attached files, we represent the body of the email with an array of &lt;code&gt;MessagePart&lt;/code&gt; objects. This class lets you access the headers and body of a message part of the email. More on it, later.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Util&lt;/code&gt; - This class contains 3 &lt;code&gt;static&lt;/code&gt; methods to parse headers, message parts, and to convert UTC date/time string to &lt;code&gt;DateTime&lt;/code&gt; object.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We will now look at the code of each of these classes in detail.&lt;/p&gt;

&lt;p&gt;The first thing we do is to import the necessary namespaces.&lt;/p&gt;

&lt;pre&gt;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Security;
using System.Net.Sockets;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using System.Xml;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;Pop3Client&lt;/code&gt; class implements &lt;code&gt;IDisposable&lt;/code&gt; interface.&lt;/p&gt;

&lt;pre&gt;
public class Pop3Client : IDisposable
{
	...
}&lt;/pre&gt;

&lt;p&gt;Following properties provide access to the variables we set in the constructor of &lt;code&gt;Pop3Client&lt;/code&gt; class.&lt;/p&gt;

&lt;pre&gt;
public string Host { get; protected set; }
public int Port { get; protected set; }
public string Email { get; protected set; }
public string Password { get; protected set; }
public bool IsSecure { get; protected set; }&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;TcpClient&lt;/code&gt; object that is used internally by &lt;code&gt;Pop3Client&lt;/code&gt; class is exposed using &lt;code&gt;Client&lt;/code&gt; property. The &lt;code&gt;ClientStream&lt;/code&gt; property is either of the &lt;code&gt;SslStream&lt;/code&gt; type if SSL is used to connect to the Pop3 server, or it is of &lt;code&gt;NetworkStream&lt;/code&gt; type if the connection is unsecure.&lt;/p&gt;

&lt;pre&gt;
public TcpClient Client { get; protected set; }
public Stream ClientStream { get; protected set; } // SslStream or NetworkStream&lt;/pre&gt;

&lt;p&gt;Since &lt;em&gt;all POP3 commands sent by the client and responses received from the server end in the new-line characters (&amp;quot;\r\n&amp;quot;)&lt;/em&gt;, we use &lt;code&gt;StreamWriter&lt;/code&gt; and &lt;code&gt;StreamReader&lt;/code&gt; classes to simplify the job of sending and receiving the data for us. You will see plenty of calls to their &lt;code&gt;WriteLine()&lt;/code&gt; and &lt;code&gt;ReadLine()&lt;/code&gt; methods, respectively, later.&lt;/p&gt;

&lt;pre&gt;
public StreamWriter Writer { get; protected set; }
public StreamReader Reader { get; protected set; }&lt;/pre&gt;

&lt;p&gt;Lastly, a &lt;code&gt;private&lt;/code&gt; variable is used to set the disposed state for this object. Remember, &lt;code&gt;Pop3Client&lt;/code&gt; class implements &lt;code&gt;IDisposable&lt;/code&gt; interface to make it easy for you to wrap access to this class in a &lt;code&gt;using&lt;/code&gt; statement.&lt;/p&gt;

&lt;pre&gt;
private bool disposed = false;&lt;/pre&gt;

&lt;p&gt;The constructor of &lt;code&gt;Pop3Client&lt;/code&gt; class takes as its arguments the name of the host you want to connect to e.g. &amp;quot;pop.gmail.com&amp;quot;, the port of the server you want to connect to e.g., 995 for Gmail, email address and password of your account on that Pop3 server. By default, the constructor will create an unsecure connection to the server. To use SSL to connect to the server, you have to set the final and optional argument to the constructor to &lt;code&gt;true&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;
public Pop3Client(string host, int port, string email, string password)
	: this(host, port, email, password, false)
{
}

public Pop3Client(string host, int port, string email,
	string password, bool secure)
{
	Host = host;
	Port = port;
	Email = email;
	Password = password;
	IsSecure = secure;
}&lt;/pre&gt;&lt;p&gt;The &lt;code&gt;Connect()&lt;/code&gt; method instantiates necessary objects and connects to the POP3 server on the given host and port. If it was specified in the constructor to open a secure connection to the POP3 server, a &lt;code&gt;SslStream&lt;/code&gt; object is created which encapsulates the &lt;code&gt;NetworkStream&lt;/code&gt; returned from the &lt;code&gt;TcpClient.GetStream()&lt;/code&gt; method. Lastly, &lt;code&gt;StreamWriter&lt;/code&gt; and &lt;code&gt;StreamReader&lt;/code&gt; objects are instantiated, and &lt;code&gt;Login()&lt;/code&gt; method is called.&lt;/p&gt;

&lt;pre&gt;
public void Connect()
{
	if (Client == null)
		Client = new TcpClient();

	if (!Client.Connected)
		Client.Connect(Host, Port);

	if (IsSecure)
	{
		SslStream secureStream =
			new SslStream(Client.GetStream());
		secureStream.AuthenticateAsClient(Host);

		ClientStream = secureStream;
		secureStream = null;
	}
	else
		ClientStream = Client.GetStream();

	Writer = new StreamWriter(ClientStream);
	Reader = new StreamReader(ClientStream);

	ReadLine();
	Login();
}&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;Login()&lt;/code&gt; method sends the user email and password to the server. Each call to send the command with required argument is sent using &lt;code&gt;SendCommand()&lt;/code&gt; method, which internally uses &lt;code&gt;StreamWriter.WriteLine()&lt;/code&gt; method to send the command. The response of the server is parsed using &lt;code&gt;IsResponseOk()&lt;/code&gt; method to determine if the response was successfull i.e., it began with an &amp;quot;+OK&amp;quot; message or if it was an error i.e., it began with an &amp;quot;-ERR&amp;quot; message. If everything went fine, the method simply returns, otherwise an &lt;code&gt;Exception&lt;/code&gt; is thrown.&lt;/p&gt;

&lt;div align="center" style="background-color: #F7F7F7;"&gt;&lt;b&gt;Note:&lt;/b&gt; All responses received from the server start with either &amp;quot;+OK&amp;quot;, if +ve response has been generated on the server, or with &amp;quot;-ERR&amp;quot;, if an error occurred.&lt;/div&gt;

&lt;pre&gt;
protected void Login()
{
	if (!IsResponseOk(SendCommand(&amp;quot;USER &amp;quot; + Email)) ||
		!IsResponseOk(SendCommand(&amp;quot;PASS &amp;quot; + Password)))
		throw new Exception(&amp;quot;User/password not accepted&amp;quot;);
}&lt;/pre&gt;

&lt;p&gt;As explained above, the &lt;code&gt;SendCommand()&lt;/code&gt; method uses &lt;code&gt;StreamWriter.WriteLine()&lt;/code&gt; to send the command to the server. We use &lt;code&gt;WriteLine()&lt;/code&gt; and not &lt;code&gt;Write()&lt;/code&gt; because each command to the server must end with new-line characters i.e., &amp;quot;\r\n&amp;quot;. Since &lt;code&gt;StreamWriter&lt;/code&gt; internally buffers the data we want sent to the server, we call its &lt;code&gt;Flush()&lt;/code&gt; method to make it send the command immediately. The response that is received from the server is fetched using &lt;code&gt;StreamReader.ReadLine()&lt;/code&gt; method and is returned to the calling code.&lt;/p&gt;

&lt;pre&gt;
protected string SendCommand(string cmdtext)
{
	Writer.WriteLine(cmdtext);
	Writer.Flush();

	return ReadLine();
}&lt;/pre&gt;

&lt;p&gt;As explained above, the &lt;code&gt;IsResponseOk()&lt;/code&gt; method parses the response received from the server and checks for the &amp;quot;+OK&amp;quot; and &amp;quot;-ERR&amp;quot; strings to determine if the response was ok or if an error has been returned.&lt;/p&gt;

&lt;pre&gt;
protected static bool IsResponseOk(string response)
{
	if (response.StartsWith(&amp;quot;+OK&amp;quot;))
		return true;
	if (response.StartsWith(&amp;quot;-ERR&amp;quot;))
		return false;

	throw new Exception(&amp;quot;Cannot understand server response: &amp;quot; +
		response);
}&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;GetEmailCount()&lt;/code&gt; returns the number of emails in the mailbox. It uses &amp;quot;&lt;code&gt;STAT&lt;/code&gt;&amp;quot; POP3 command to retrieve the number of emails. As you can see in the code below, the response of the server is parsed and the word containing number of emails is taken and converted to an &lt;code&gt;integer&lt;/code&gt;, which is then returned to the calling code.&lt;/p&gt;

&lt;pre&gt;
public int GetEmailCount()
{
	int count = 0;
	string response = SendCommand(&amp;quot;STAT&amp;quot;);

	if (IsResponseOk(response))
	{
		string[] arr = response.Substring(4).Split(&amp;apos; &amp;apos;);
		count = Convert.ToInt32(arr[0]);
	}
	else
		count = -1;

	return count;
}&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;FetchEmail()&lt;/code&gt; takes the sort number of the email as its argument and retrieves the headers for that email using &amp;quot;TOP&amp;quot; POP3 command. This command takes two parameters, the sort no of email and the number of lines of the body of email you want to fetch. We give this command the sort no of the email to fetch and 0 (zero) as the number of lines of text to retrieve from the body of the email. We set the second parameter to 0 because we only want to retrieve headers. The headers returned are used to instantiate &lt;code&gt;Email&lt;/code&gt; object and that is then returned to the calling code.&lt;/p&gt;

&lt;pre&gt;
public Email FetchEmail(int emailId)
{
	if (IsResponseOk(SendCommand(&amp;quot;TOP &amp;quot; + emailId + &amp;quot; 0&amp;quot;)))
		return new Email(ReadLines());
	else
		return null;
}&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;FetchEmailList()&lt;/code&gt; fetches the email headers, using &lt;code&gt;FetchEmail()&lt;/code&gt; method, of given number of emails starting from given sort number. For instance, you have 300 emails in your mailbox and want to now display a list of 10 emails from 150 to 160, you should call this method as: &lt;code&gt;FetchEmailList(151, 10)&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;
 public List&amp;lt;Email&amp;gt; FetchEmailList(int start, int count)
{
	List&amp;lt;Email&amp;gt; emails = new List&amp;lt;Email&amp;gt;(count);

	for (int i = start; i &amp;lt; (start + count); i++)
	{
		Email email = FetchEmail(i);

		if (email != null)
			emails.Add(email);
	}

	return emails;
}&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;FetchMessageParts()&lt;/code&gt; retrieves an email from the server and then parses its body into an array of &lt;code&gt;MessagePart&lt;/code&gt; objects. Each &lt;code&gt;MessagePart&lt;/code&gt; object encapsulates one part of the body of the email and any attached files.&lt;/p&gt;

&lt;pre&gt;
public List&amp;lt;MessagePart&amp;gt; FetchMessageParts(int emailId)
{
	if (IsResponseOk(SendCommand(&amp;quot;RETR &amp;quot; + emailId)))
		return Util.ParseMessageParts(ReadLines());

	return null;
}&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;Close()&lt;/code&gt; logs out the user, closes the connection, and properly disposes all the &lt;code&gt;Stream&lt;/code&gt; objects in use.&lt;/p&gt;

&lt;pre&gt;
public void Close()
{
	if (Client != null)
	{
		if (Client.Connected)
			Logout();

		Client.Close();
		Client = null;
	}

	if (ClientStream != null)
	{
		ClientStream.Close();
		ClientStream = null;
	}

	if (Writer != null)
	{
		Writer.Close();
		Writer = null;
	}

	if (Reader != null)
	{
		Reader.Close();
		Reader = null;
	}

	disposed = true;
}&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;Dispose()&lt;/code&gt; method is implemented as part of the implementation of &lt;code&gt;IDisposable&lt;/code&gt; interface. It calls the &lt;code&gt;Close()&lt;/code&gt; method above if not already called.&lt;/p&gt;

&lt;pre&gt;
public void Dispose()
{
	if (!disposed)
		Close();
}&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;Logout()&lt;/code&gt; method does nothing but to send the &amp;quot;&lt;code&gt;RSET&lt;/code&gt;&amp;quot; command to the server which resets the server meaning there by that if any emails were marked as deleted, they are unmarked. Although no part in our code marks the emails to be deleted, we call it anyway.&lt;/p&gt;

&lt;pre&gt;
protected void Logout()
{
	SendCommand(&amp;quot;RSET&amp;quot;);
}&lt;/pre&gt;

&lt;p&gt;We will now look at the code that constitutes the &lt;code&gt;Email&lt;/code&gt; class.&lt;/p&gt;

&lt;pre&gt;
public class Email
{
	...
}&lt;/pre&gt;

&lt;p&gt;An &lt;code&gt;Email&lt;/code&gt; object represents an email on the server minus its body. It contains all the headers contained in an email. It provides access to the headers' collection using &lt;code&gt;Headers&lt;/code&gt; property. Commonly used headers like &amp;quot;&lt;em&gt;From&lt;/em&gt;&amp;quot;, &amp;quot;&lt;em&gt;To&lt;/em&gt;&amp;quot;, &amp;quot;&lt;em&gt;Subject&lt;/em&gt;&amp;quot;, &amp;quot;&lt;em&gt;Date&lt;/em&gt;&amp;quot;, &amp;quot;&lt;em&gt;Content-Type&lt;/em&gt;&amp;quot; can be accessed using properites like &lt;code&gt;From&lt;/code&gt;, &lt;code&gt;To&lt;/code&gt;, &lt;code&gt;Subject&lt;/code&gt;, &lt;code&gt;UtcDateTime&lt;/code&gt;, and &lt;code&gt;ContentType&lt;/code&gt;, respectively.&lt;/p&gt;&lt;div align="center" style="background-color: #F7F7F7;"&gt;&lt;b&gt;Note:&lt;/b&gt; The purpose of properties mentioned above is only to provide easy access to header fields. For practical purposes code like &lt;code&gt;Email.Headers["From"]&lt;/code&gt; and &lt;code&gt;Email.From&lt;/code&gt; will yield the same value. And if any of these headers is not found in the email, the property will return &lt;code&gt;null&lt;/code&gt;.&lt;/div&gt;

&lt;pre&gt;
public NameValueCollection Headers { get; protected set; }

public string ContentType { get; protected set; }
public DateTime UtcDateTime { get; protected set; }
public string From { get; protected set; }
public string To { get; protected set; }
public string Subject { get; protected set; }&lt;/pre&gt;

&lt;p&gt;Within the constructor of &lt;code&gt;Email&lt;/code&gt; class, we retrieve header fields as &lt;code&gt; a NameValueCollection&lt;/code&gt; object using &lt;code&gt;Util.ParseHeaders()&lt;/code&gt; method. Once we have the collection, we set the properties to the values retrieved from the header fields.&lt;/p&gt;

&lt;p&gt;Unlike other properties, the property &lt;code&gt;Date&lt;/code&gt; is not of type &lt;code&gt;string&lt;/code&gt;. It is of type &lt;code&gt;DateTime&lt;/code&gt;. We parse the &lt;code&gt;Headers[&amp;quot;Date&amp;quot;]&lt;/code&gt; header string and convert it in to a &lt;code&gt;DateTime&lt;/code&gt; structure using &lt;code&gt;Util.ConvertStrToUtcDateTime()&lt;/code&gt; method.&lt;/p&gt;

&lt;pre&gt;
public Email(string emailText)
{
	Headers = Util.ParseHeaders(emailText);

	ContentType = Headers[&amp;quot;Content-Type&amp;quot;];
	From = Headers[&amp;quot;From&amp;quot;];
	To = Headers[&amp;quot;To&amp;quot;];
	Subject = Headers[&amp;quot;Subject&amp;quot;];

	if (Headers[&amp;quot;Date&amp;quot;] != null)
		try
		{
			UtcDateTime = Util.ConvertStrToUtcDateTime(Headers[&amp;quot;Date&amp;quot;]);
		}
		catch (FormatException)
		{
			UtcDateTime = DateTime.MinValue;
		}
	else
		UtcDateTime = DateTime.MinValue;
}&lt;/pre&gt;

&lt;p&gt;We will now look at the code of &lt;code&gt;MessagePart&lt;/code&gt; class.&lt;/p&gt;

&lt;pre&gt;
public class MessagePart
{
	...
}&lt;/pre&gt;

&lt;p&gt;A &lt;code&gt;MessagePart&lt;/code&gt; object represents just one component of the body of an email. Remember, that most emails are MIME compatible and have multiple parts that form the body of that email.&lt;/p&gt;

&lt;p&gt;For instance, you send an HTML email to a person. Just in case if the person is using an email client that cannot render HTML emails, either you or your email client also creates a plain text version of the email and appends it to the email. Now your email has two parts; one is of &lt;code&gt;text/html&lt;/code&gt; content-type and the other is of &lt;code&gt;text/plain&lt;/code&gt; content-type. The email client of the person you sent that email to will upon receiving that email try to find a plain text version of the email so that it can display that to the person without any difficulty. On searching through the MIME compatible email's message parts, it finds a version of &lt;code&gt;text/plain&lt;/code&gt; content-type. It parses and decodes (if needed) it and displays it to that person.&lt;/p&gt;

&lt;p&gt;Now if you had attached 2 files with that email, the total message parts would have become four:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;HTML version of the email - &lt;code&gt;text/html&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Plain text version of the email - &lt;code&gt;text/plain&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Attached File #1 - &lt;code&gt;base64&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Attached File #2 - &lt;code&gt;base64&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now upon parsing this email using the code above, you'll have an array of four &lt;code&gt;MessagePart&lt;/code&gt; objects. I hope you understand now what &lt;code&gt;MessagePart&lt;/code&gt; represents.&lt;/p&gt;

&lt;div align="center" style="background-color: #F7F7F7;"&gt;&lt;b&gt;Note:&lt;/b&gt; &lt;em&gt;&lt;code&gt;base64&lt;/code&gt; is a content-transfer-encoding for sending binary data like images files, in a text based email message.&lt;/em&gt;&lt;/div&gt;

&lt;p&gt;It has a &lt;code&gt;Headers&lt;/code&gt; property that makes available all the headers that this message part contains. The &lt;code&gt;ContentType&lt;/code&gt; property is there to easily access the &lt;code&gt;Headers[&amp;quot;Content-Type&amp;quot;]&lt;/code&gt; field. The &lt;code&gt;MessageText&lt;/code&gt; property makes available the content of the body of this message part.&lt;/p&gt;

&lt;pre&gt;
public NameValueCollection Headers { get; protected set; }

public string ContentType { get; protected set; }
public string MessageText { get; protected set; }&lt;/pre&gt;

&lt;p&gt;In the constructor, we set the properties.&lt;/p&gt;

&lt;pre&gt;
public MessagePart(NameValueCollection headers, string messageText)
{
	Headers = headers;
	ContentType = Headers[&amp;quot;Content-Type&amp;quot;];
	MessageText = messageText;
}&lt;/pre&gt;

&lt;p&gt;We will now look at the code of &lt;code&gt;Util&lt;/code&gt; class, which contains 3 &lt;code&gt;static&lt;/code&gt; methods.&lt;/p&gt;

&lt;pre&gt;
public class Util
{
	...
}&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;ParseHeaders()&lt;/code&gt; parses all the headers and converts them into easily accessible &lt;code&gt;NameValueCollection&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;
public static NameValueCollection ParseHeaders(string headerText)
{
	NameValueCollection headers = new NameValueCollection();
	StringReader reader = new StringReader(headerText);

	string line;
	string headerName = null, headerValue;
	int colonIndx;

	while ((line = reader.ReadLine()) != null)
	{
		if (line == &amp;quot;&amp;quot;)
			break;

		if (Char.IsLetterOrDigit(line[0]) &amp;amp;&amp;amp; (colonIndx = line.IndexOf(&amp;apos;:&amp;apos;)) != -1)
		{
			headerName = line.Substring(0, colonIndx);
			headerValue = line.Substring(colonIndx + 1).Trim();

			headers.Add(headerName, headerValue);
		}
		else if (headerName != null)
			headers[headerName] += &amp;quot; &amp;quot; + line.Trim();
		else
			throw new FormatException(&amp;quot;Could not parse headers&amp;quot;);
	}

	return headers;
}&lt;/pre&gt;&lt;p&gt;&lt;code&gt;ParseMessageParts()&lt;/code&gt; parses the body of an email and separates the body into separate message parts using the boundary header.&lt;/p&gt;

&lt;pre&gt;
public static List&amp;lt;MessagePart&amp;gt; ParseMessageParts(string emailText)
    {
      List&amp;lt;MessagePart&amp;gt; messageParts = new List&amp;lt;MessagePart&amp;gt;();
      int newLinesIndx = emailText.IndexOf(&amp;quot;\r\n\r\n&amp;quot;);

      Match m = BoundaryRegex.Match(emailText);

      if (m.Index &amp;lt; emailText.IndexOf(&amp;quot;\r\n\r\n&amp;quot;) &amp;amp;&amp;amp; m.Success)
      {
        string boundary = m.Groups[&amp;quot;boundary&amp;quot;].Value;
        string startingBoundary = &amp;quot;\r\n--&amp;quot; + boundary;

        int startingBoundaryIndx = -1;

        while (true)
        {
          if (startingBoundaryIndx == -1)
            startingBoundaryIndx = emailText.IndexOf(startingBoundary);

          if (startingBoundaryIndx != -1)
          {
            int nextBoundaryIndx = emailText.IndexOf(startingBoundary,
              startingBoundaryIndx + startingBoundary.Length);

            if (nextBoundaryIndx != -1 &amp;amp;&amp;amp; nextBoundaryIndx != startingBoundaryIndx)
            {
              string multipartMsg = emailText.Substring(startingBoundaryIndx +
                startingBoundary.Length,
                (nextBoundaryIndx - startingBoundaryIndx - startingBoundary.Length));

              int headersIndx = multipartMsg.IndexOf(&amp;quot;\r\n\r\n&amp;quot;);

              if (headersIndx == -1)
                throw new FormatException(&amp;quot;Incompatible multipart message format&amp;quot;);

              string bodyText = multipartMsg.Substring(headersIndx).Trim();

              NameValueCollection headers = Util.ParseHeaders(multipartMsg.Trim());
              messageParts.Add(new MessagePart(headers, bodyText));
            }
            else
              break;

            startingBoundaryIndx = nextBoundaryIndx;
          }
          else
            break;
        }

        if (newLinesIndx != -1)
        {
          string emailBodyText = emailText.Substring(newLinesIndx + 1);
        }
      }
      else
      {
        int headersIndx = emailText.IndexOf(&amp;quot;\r\n\r\n&amp;quot;);

        if (headersIndx == -1)
          throw new FormatException(&amp;quot;Incompatible multipart message format&amp;quot;);

        string bodyText = emailText.Substring(headersIndx).Trim();

        NameValueCollection headers = Util.ParseHeaders(emailText);
        messageParts.Add(new MessagePart(headers, bodyText));
      }

      return messageParts;
    }&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;ConvertStrToUtcDateTime()&lt;/code&gt; parses a date &amp;amp; time string and converts it into a &lt;code&gt;DateTime&lt;/code&gt; structure. It makes use of a regular expression to parse individual components from the date &amp;amp; time string.&lt;/p&gt;

&lt;pre&gt;
public static DateTime ConvertStrToUtcDateTime(string str)
{
	Match m = UtcDateTimeRegex.Match(str);

	int day, month, year, hour, min, sec;

	if (m.Success)
	{
		day = Convert.ToInt32(m.Groups[&amp;quot;day&amp;quot;].Value);
		year = Convert.ToInt32(m.Groups[&amp;quot;year&amp;quot;].Value);
		hour = Convert.ToInt32(m.Groups[&amp;quot;hour&amp;quot;].Value);
		min = Convert.ToInt32(m.Groups[&amp;quot;minute&amp;quot;].Value);
		sec = Convert.ToInt32(m.Groups[&amp;quot;second&amp;quot;].Value);

		switch (m.Groups[&amp;quot;month&amp;quot;].Value)
		{
			case &amp;quot;Jan&amp;quot;:
				month = 1;
				break;
			case &amp;quot;Feb&amp;quot;:
				month = 2;
				break;
			case &amp;quot;Mar&amp;quot;:
				month = 3;
				break;
			case &amp;quot;Apr&amp;quot;:
				month = 4;
				break;
			case &amp;quot;May&amp;quot;:
				month = 5;
				break;
			case &amp;quot;Jun&amp;quot;:
				month = 6;
				break;
			case &amp;quot;Jul&amp;quot;:
				month = 7;
				break;
			case &amp;quot;Aug&amp;quot;:
				month = 8;
				break;
			case &amp;quot;Sep&amp;quot;:
				month = 9;
				break;
			case &amp;quot;Oct&amp;quot;:
				month = 10;
				break;
			case &amp;quot;Nov&amp;quot;:
				month = 11;
				break;
			case &amp;quot;Dec&amp;quot;:
				month = 12;
				break;
			default:
				throw new FormatException(&amp;quot;Unknown month.&amp;quot;);
		}

		string offsetSign = m.Groups[&amp;quot;offsetsign&amp;quot;].Value;
		int offsetHours = Convert.ToInt32(m.Groups[&amp;quot;offsethours&amp;quot;].Value);
		int offsetMinutes = Convert.ToInt32(m.Groups[&amp;quot;offsetminutes&amp;quot;].Value);

		DateTime dt = new DateTime(year, month, day, hour, min, sec);

		if (offsetSign == &amp;quot;+&amp;quot;)
		{
			dt.AddHours(offsetHours);
			dt.AddMinutes(offsetMinutes);
		}
		else if (offsetSign == &amp;quot;-&amp;quot;)
		{
			dt.AddHours(-offsetHours);
			dt.AddMinutes(-offsetMinutes);
		}

		return dt;
	}

	throw new FormatException(&amp;quot;Incompatible date/time string format&amp;quot;);
}&lt;/pre&gt;

&lt;p&gt;Now that we have created the necessary classes, we will create the front-end ASP.NET page to display the list of emails to the user.&lt;/p&gt;&lt;p&gt;&lt;b&gt;ii. Pop3Client.aspx&lt;/b&gt;&lt;br /&gt;
Open Notepad and copy following text in it, and then save it as &amp;quot;Pop3Client.aspx&amp;quot; in your ASP.NET web application:&lt;/p&gt;

&lt;pre&gt;
&amp;lt;%@ Page Language=&amp;quot;C#&amp;quot; %&amp;gt;

&amp;lt;%@ Import Namespace=&amp;quot;System.Collections.Generic&amp;quot; %&amp;gt;
&amp;lt;%@ Import Namespace=&amp;quot;Stardeveloper.Pop3&amp;quot; %&amp;gt;

&amp;lt;script runat=&amp;quot;server&amp;quot;&amp;gt;
	public const string Host = &amp;quot;pop.gmail.com&amp;quot;;
	public const int Port = 995;
	public const string Email = &amp;quot;youremail@gmail.com&amp;quot;;
	public const string Password = &amp;quot;yourpassword&amp;quot;;

	public const int NoOfEmailsPerPage = 5;
	public const string SelfLink =
		&amp;quot;&amp;lt;a href=\&amp;quot;Pop3Client.aspx?page={0}\&amp;quot;&amp;gt;{1}&amp;lt;/a&amp;gt;&amp;quot;;
	public const string DisplayEmailLink =
		&amp;quot;&amp;lt;a href=\&amp;quot;DisplayPop3Email.aspx?emailId={0}\&amp;quot;&amp;gt;{1}&amp;lt;/a&amp;gt;&amp;quot;;

	protected void Page_Load(object source, EventArgs e)
	{
		/* Setting current page */
		int page = 1;

		if (Request.QueryString[&amp;quot;page&amp;quot;] == null)
		{
			Response.Redirect(&amp;quot;Pop3Client.aspx?page=1&amp;quot;);
			Response.Flush();
			Response.End();
		}
		else
			page = Convert.ToInt32(Request.QueryString[&amp;quot;page&amp;quot;]);

		/* Creating Pop3Client object and accessing email data */
		int totalEmails;
		List&amp;lt;Email&amp;gt; emails;
		string emailAddress;

		using(Pop3Client client = new Pop3Client(Host, Port, Email, Password, true))
		{
			emailAddress = client.Email;

			client.Connect();

			totalEmails = client.GetEmailCount();
			emails = client.FetchEmailList(((page - 1) *
				NoOfEmailsPerPage) + 1, NoOfEmailsPerPage);
		}

		/* Computing total pages */
		int totalPages;
		int mod = totalEmails % NoOfEmailsPerPage;

		if (mod == 0)
			totalPages = totalEmails / NoOfEmailsPerPage;
		else
			totalPages = ((totalEmails - mod) / NoOfEmailsPerPage) + 1;

		for (int i = 0; i &amp;lt; emails.Count; i++)
		{
			Email email = emails[i];

			/* Appending each email to an existing table */
			int emailId = ((page - 1) * NoOfEmailsPerPage) + i + 1;

			TableCell noCell = new TableCell();
			noCell.CssClass = &amp;quot;emails-table-cell&amp;quot;;
			noCell.Text = Convert.ToString(emailId);
			
			TableCell fromCell = new TableCell();
			fromCell.CssClass = &amp;quot;emails-table-cell&amp;quot;;
			fromCell.Text = email.From;
			
			TableCell subjectCell = new TableCell();
			subjectCell.CssClass = &amp;quot;emails-table-cell&amp;quot;;
			subjectCell.Style[&amp;quot;width&amp;quot;] = &amp;quot;300px&amp;quot;;
			subjectCell.Text = String.Format(DisplayEmailLink,
				emailId, email.Subject);

			//TableCell contentTypeCell = new TableCell();
			//contentTypeCell.CssClass = &amp;quot;emails-table-cell&amp;quot;;
			//contentTypeCell.Text = email.ContentType;
			
			TableCell dateCell = new TableCell();
			dateCell.CssClass = &amp;quot;emails-table-cell&amp;quot;;
			
			if (email.UtcDateTime != DateTime.MinValue)
				dateCell.Text = email.UtcDateTime.ToString();

			TableRow emailRow = new TableRow();
			emailRow.Cells.Add(noCell);
			emailRow.Cells.Add(fromCell);
			emailRow.Cells.Add(subjectCell);
			//emailRow.Cells.Add(contentTypeCell);
			emailRow.Cells.Add(dateCell);

			EmailsTable.Rows.AddAt(2 + i, emailRow);
		}

		/* Creating links to previous and next pages */
		if (totalPages &amp;gt; 1)
		{
			if (page &amp;gt; 1)
				PreviousPageLiteral.Text =
					String.Format(SelfLink, page - 1, &amp;quot;Previous Page&amp;quot;);

			if (page &amp;gt; 0 &amp;amp;&amp;amp; page &amp;lt; totalPages)
				NextPageLiteral.Text =
					String.Format(SelfLink, page + 1, &amp;quot;Next Page&amp;quot;);
		}

		/* Displaying information to the user */
		EmailFromLiteral.Text =
			Convert.ToString(((page - 1) * NoOfEmailsPerPage) + 1);
		EmailToLiteral.Text = Convert.ToString(page * NoOfEmailsPerPage);
		EmailTotalLiteral.Text = Convert.ToString(totalEmails);
		EmailLiteral.Text = emailAddress;
	}
&amp;lt;/script&amp;gt;

&amp;lt;!DOCTYPE html PUBLIC &amp;quot;-//W3C//DTD XHTML 1.0 Transitional//EN&amp;quot;
	&amp;quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&amp;quot;&amp;gt;

&amp;lt;html xmlns=&amp;quot;http://www.w3.org/1999/xhtml&amp;quot;&amp;gt;
&amp;lt;head runat=&amp;quot;server&amp;quot;&amp;gt;
    &amp;lt;title&amp;gt;&amp;lt;/title&amp;gt;
    &amp;lt;style type=&amp;quot;text/css&amp;quot;&amp;gt;
		.emails-table { width: 600px; border: solid 1px #444444; }
		.emails-table-header { font-family: &amp;quot;Trebuchet MS&amp;quot;; font-size: 9pt;
			background-color: #0099B9; color: white;
			border: solid 1px #444444; }
		.emails-table-header-cell { font-family: &amp;quot;Georgia&amp;quot;; font-size: 9pt;
			font-weight: bold; border: solid 1px #666666; padding: 6px; }
		.emails-table-cell { font-family: &amp;quot;Georgia&amp;quot;; font-size: 9pt;
			border: solid 1px #666666; padding: 6px; }
		.emails-table-footer { border: solid 1px #666666; padding: 3px;
			width: 50%; }
		.email-datetime { float: right; color: #666666; }
		
		a { font-family: &amp;quot;Lucida Sans Unicode&amp;quot;, &amp;quot;Trebuchet MS&amp;quot;; font-size: 9pt;
			color: #005B7F; }
		a:hover { color:red; }
    &amp;lt;/style&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
    &amp;lt;form id=&amp;quot;form1&amp;quot; runat=&amp;quot;server&amp;quot;&amp;gt;
    &amp;lt;div&amp;gt;
		&amp;lt;asp:Table ID=&amp;quot;EmailsTable&amp;quot; CssClass=&amp;quot;emails-table&amp;quot; runat=&amp;quot;server&amp;quot;&amp;gt;
		&amp;lt;asp:TableHeaderRow&amp;gt;
			&amp;lt;asp:TableHeaderCell CssClass=&amp;quot;emails-table-header&amp;quot;
				ColumnSpan=&amp;quot;4&amp;quot;&amp;gt;Listing emails 
			&amp;lt;asp:Literal ID=&amp;quot;EmailFromLiteral&amp;quot; runat=&amp;quot;server&amp;quot; /&amp;gt;-
			&amp;lt;asp:Literal ID=&amp;quot;EmailToLiteral&amp;quot; runat=&amp;quot;server&amp;quot; /&amp;gt; of 
			&amp;lt;asp:Literal ID=&amp;quot;EmailTotalLiteral&amp;quot; runat=&amp;quot;server&amp;quot; /&amp;gt; for 
			&amp;lt;asp:Literal ID=&amp;quot;EmailLiteral&amp;quot; runat=&amp;quot;server&amp;quot; /&amp;gt;
			&amp;lt;/asp:TableHeaderCell&amp;gt;
		&amp;lt;/asp:TableHeaderRow&amp;gt;
		&amp;lt;asp:TableRow&amp;gt;
			&amp;lt;asp:TableCell CssClass=&amp;quot;emails-table-header-cell&amp;quot;&amp;gt;
				#&amp;lt;/asp:TableCell&amp;gt;
			&amp;lt;asp:TableCell CssClass=&amp;quot;emails-table-header-cell&amp;quot;&amp;gt;
				From&amp;lt;/asp:TableCell&amp;gt;
			&amp;lt;asp:TableCell CssClass=&amp;quot;emails-table-header-cell&amp;quot;&amp;gt;
				Subject&amp;lt;/asp:TableCell&amp;gt;
			&amp;lt;asp:TableCell CssClass=&amp;quot;emails-table-header-cell&amp;quot;&amp;gt;
				Date &amp;amp;amp; Time&amp;lt;/asp:TableCell&amp;gt;
		&amp;lt;/asp:TableRow&amp;gt;
		&amp;lt;asp:TableFooterRow&amp;gt;
			&amp;lt;asp:TableCell CssClass=&amp;quot;emails-table-footer&amp;quot; ColumnSpan=&amp;quot;4&amp;quot;&amp;gt;
			&amp;lt;asp:Table ID=&amp;quot;FooterTable&amp;quot; Width=&amp;quot;100%&amp;quot;
				BorderWidth=&amp;quot;0&amp;quot; runat=&amp;quot;server&amp;quot;&amp;gt;
			&amp;lt;asp:TableRow&amp;gt;
			&amp;lt;asp:TableCell&amp;gt;
				&amp;lt;asp:Literal ID=&amp;quot;PreviousPageLiteral&amp;quot; runat=&amp;quot;server&amp;quot; /&amp;gt;
			&amp;lt;/asp:TableCell&amp;gt;
			&amp;lt;asp:TableCell HorizontalAlign=&amp;quot;Right&amp;quot;&amp;gt;
				&amp;lt;asp:Literal ID=&amp;quot;NextPageLiteral&amp;quot; runat=&amp;quot;server&amp;quot; /&amp;gt;
			&amp;lt;/asp:TableCell&amp;gt;
			&amp;lt;/asp:TableRow&amp;gt;
			&amp;lt;/asp:Table&amp;gt;
			&amp;lt;/asp:TableCell&amp;gt;
		&amp;lt;/asp:TableFooterRow&amp;gt;
		&amp;lt;/asp:Table&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;/form&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/pre&gt;

&lt;p&gt;&lt;b&gt;Explanation&lt;/b&gt;&lt;br /&gt;
This ASP.NET page is responsible for using the &lt;code&gt;Pop3Client&lt;/code&gt; class we developed earlier to display list of emails in Gmail's mailbox, page by page. The user will be able to browse all the pages using &amp;apos;Next Page&amp;apos; and &amp;apos;Previous Page&amp;apos; links.&lt;/p&gt;

&lt;p&gt;The first thing we do is to declare a &lt;code&gt;Page&lt;/code&gt; level directive and tell the ASP.NET compiler that the language we are going to use on this page is &amp;quot;C#&amp;quot;.&lt;/p&gt;

&lt;pre&gt;
&amp;lt;%@ Page Language=&amp;quot;C#&amp;quot; %&amp;gt;&lt;/pre&gt;&lt;p&gt;Next, we import the necessary namespaces.&lt;/p&gt;

&lt;pre&gt;
&amp;lt;%@ Import Namespace=&amp;quot;System.Collections.Generic&amp;quot; %&amp;gt;
&amp;lt;%@ Import Namespace=&amp;quot;Stardeveloper.Pop3&amp;quot; %&amp;gt;&lt;/pre&gt;

&lt;p&gt;The server-side code is encapsulated between the &lt;code&gt;&amp;lt;script&amp;gt;&amp;lt;/script&amp;gt;&lt;/code&gt; tags.&lt;/p&gt;

&lt;pre&gt;
&amp;lt;script runat=&amp;quot;server&amp;quot;&amp;gt;
	...
&amp;lt;/script&amp;gt;&lt;/pre&gt;

&lt;p&gt;We declare a few constants. The first four are required to properly connect and login to the Gmail's POP3 server. The &lt;code&gt;Host&lt;/code&gt; and &lt;code&gt;Port&lt;/code&gt; constants can be changed to point to your email provider's POP3 server, if it is not Gmail. For the purpose of demonstration, we will connect to Gmail's POP3 server. &lt;em&gt;The &lt;code&gt;Email&lt;/code&gt; and &lt;code&gt;Password&lt;/code&gt; constants should be changed to your email address and password&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;NoOfEmailsPerPage&lt;/code&gt; constant is used to declare how many emails we want to show per page. You can change it to &lt;code&gt;10&lt;/code&gt; or &lt;code&gt;20&lt;/code&gt; to suit the needs of your web application. &lt;code&gt;SelfLink&lt;/code&gt; and &lt;code&gt;DisplayLink&lt;/code&gt; constants contain strings for formatting links and to display the full email in the &amp;quot;&lt;code&gt;DisplayPop3Email.aspx&lt;/code&gt;&amp;quot; ASP.NET page, which we will create in the next tutorial.&lt;/p&gt;

&lt;pre&gt;
public const string Host = &amp;quot;pop.gmail.com&amp;quot;;
public const int Port = 995;
public const string Email = &amp;quot;youremail@gmail.com&amp;quot;;
public const string Password = &amp;quot;yourpassword&amp;quot;;

public const int NoOfEmailsPerPage = 5;
public const string SelfLink =
	&amp;quot;&amp;lt;a href=\&amp;quot;Pop3Client.aspx?page={0}\&amp;quot;&amp;gt;{1}&amp;lt;/a&amp;gt;&amp;quot;;
public const string DisplayEmailLink =
	&amp;quot;&amp;lt;a href=\&amp;quot;DisplayPop3Email.aspx?emailId={0}\&amp;quot;&amp;gt;{1}&amp;lt;/a&amp;gt;&amp;quot;;&lt;/pre&gt;

&lt;p&gt;Now we will dig into the all important code in the &lt;code&gt;Page_Load()&lt;/code&gt; method.&lt;/p&gt;

&lt;pre&gt;
protected void Page_Load(object source, EventArgs e)
{
	...
}&lt;/pre&gt;

&lt;p&gt;If you access &lt;code&gt;Pop3Client.aspx&lt;/code&gt; directly, it will redirect you to &lt;code&gt;Pop3Client.aspx?page=1&lt;/code&gt;. The current page is retrieved and saved in the &lt;code&gt;page&lt;/code&gt; variable.&lt;/p&gt;

&lt;pre&gt;
/* Setting current page */
int page = 1;

if (Request.QueryString[&amp;quot;page&amp;quot;] == null)
{
	Response.Redirect(&amp;quot;Pop3Client.aspx?page=1&amp;quot;);
	Response.Flush();
	Response.End();
}
else
	page = Convert.ToInt32(Request.QueryString[&amp;quot;page&amp;quot;]);&lt;/pre&gt;

&lt;p&gt;Now we create the &lt;code&gt;Pop3Client&lt;/code&gt; object. We create it within the &lt;code&gt;using&lt;/code&gt; statement so that we don't explicitly have to call the &lt;code&gt;Pop3Client.Close()&lt;/code&gt; method. Gorgeous!&lt;/p&gt;

&lt;p&gt;We call the &lt;code&gt;GetEmailCount()&lt;/code&gt; method to get the number of emails in the mailbox. Next, we retrieve the list of emails for the current page.&lt;/p&gt;

&lt;div align="center" style="background-color: #F7F7F7;"&gt;&lt;b&gt;Note:&lt;/b&gt; The number of emails in the list will be a maximum of &lt;code&gt;NoOfEmailsPerPage&lt;/code&gt; i.e., &lt;code&gt;5&lt;/code&gt;. We do not retrieve all the emails in the mailbox. We retrieve only those that are required to be displayed on the &lt;em&gt;current&lt;/em&gt; page.&lt;/div&gt;

&lt;pre&gt;
/* Creating Pop3Client object and accessing email data */
int totalEmails;
List&amp;lt;Email&amp;gt; emails;
string emailAddress;

using(Pop3Client client = new Pop3Client(Host, Port, Email, Password, true))
{
	emailAddress = client.Email;

	client.Connect();

	totalEmails = client.GetEmailCount();
	emails = client.FetchEmailList(((page - 1) *
		NoOfEmailsPerPage) + 1, NoOfEmailsPerPage);
}&lt;/pre&gt;

&lt;p&gt;Next, we compute the total number of pages the user can browse through.&lt;/p&gt;

&lt;pre&gt;
/* Computing total pages */
int totalPages;
int mod = totalEmails % NoOfEmailsPerPage;

if (mod == 0)
	totalPages = totalEmails / NoOfEmailsPerPage;
else
	totalPages = ((totalEmails - mod) / NoOfEmailsPerPage) + 1;&lt;/pre&gt;

&lt;p&gt;Next, we iterate through the retrieved list of emails, one by one, and append their information to an HTML table which we will display to the user.&lt;/p&gt;

&lt;pre&gt;
for (int i = 0; i &amp;lt; emails.Count; i++)
{
	Email email = emails[i];

	/* Appending each email to an existing table */
	int emailId = ((page - 1) * NoOfEmailsPerPage) + i + 1;

	TableCell noCell = new TableCell();
	noCell.CssClass = &amp;quot;emails-table-cell&amp;quot;;
	noCell.Text = Convert.ToString(emailId);
	
	TableCell fromCell = new TableCell();
	fromCell.CssClass = &amp;quot;emails-table-cell&amp;quot;;
	fromCell.Text = email.From;
	
	TableCell subjectCell = new TableCell();
	subjectCell.CssClass = &amp;quot;emails-table-cell&amp;quot;;
	subjectCell.Style[&amp;quot;width&amp;quot;] = &amp;quot;300px&amp;quot;;
	subjectCell.Text = String.Format(DisplayEmailLink,
		emailId, email.Subject);

	//TableCell contentTypeCell = new TableCell();
	//contentTypeCell.CssClass = &amp;quot;emails-table-cell&amp;quot;;
	//contentTypeCell.Text = email.ContentType;
	
	TableCell dateCell = new TableCell();
	dateCell.CssClass = &amp;quot;emails-table-cell&amp;quot;;
	
	if (email.UtcDateTime != DateTime.MinValue)
		dateCell.Text = email.UtcDateTime.ToString();

	TableRow emailRow = new TableRow();
	emailRow.Cells.Add(noCell);
	emailRow.Cells.Add(fromCell);
	emailRow.Cells.Add(subjectCell);
	//emailRow.Cells.Add(contentTypeCell);
	emailRow.Cells.Add(dateCell);

	EmailsTable.Rows.AddAt(2 + i, emailRow);
}&lt;/pre&gt;

&lt;p&gt;Next, we create &amp;apos;Previous Page&amp;apos; and &amp;apos;Next Page&amp;apos; links.&lt;/p&gt;

&lt;pre&gt;
/* Creating links to previous and next pages */
if (totalPages &amp;gt; 1)
{
	if (page &amp;gt; 1)
		PreviousPageLiteral.Text =
			String.Format(SelfLink, page - 1, &amp;quot;Previous Page&amp;quot;);

	if (page &amp;gt; 0 &amp;amp;&amp;amp; page &amp;lt; totalPages)
		NextPageLiteral.Text =
			String.Format(SelfLink, page + 1, &amp;quot;Next Page&amp;quot;);
}&lt;/pre&gt;

&lt;p&gt;Lastly, we set a few literals to display on the page.&lt;/p&gt;

&lt;pre&gt;
/* Displaying information to the user */
EmailFromLiteral.Text =
	Convert.ToString(((page - 1) * NoOfEmailsPerPage) + 1);
EmailToLiteral.Text = Convert.ToString(page * NoOfEmailsPerPage);
EmailTotalLiteral.Text = Convert.ToString(totalEmails);
EmailLiteral.Text = emailAddress;&lt;/pre&gt;

&lt;p&gt;We are now all set to run this page on our ASP.NET web server. But before that, there is one final step left, and that is to &lt;em&gt;enable POP3 access for our mailbox on Gmail&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Enabling POP3 access on Gmail&lt;/b&gt;&lt;br /&gt;
Follow these steps to enable POP3 access for your email address on Gmail:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Login to your account at Gmail.&lt;/li&gt;
&lt;li&gt;Click the &amp;quot;Settings&amp;quot; link on the top right.&lt;/li&gt;
&lt;li&gt;From the &amp;apos;Settings&amp;apos; panel, click the &amp;quot;Forwarding and POP/IMAP&amp;quot; tab.&lt;/li&gt;
&lt;li&gt;In the &amp;apos;POP Download&amp;apos; section, select the option &amp;quot;Enable POP for all mail (even mail that's already been downloaded)&amp;quot;&lt;/li&gt;
&lt;li&gt;Make sure &amp;apos;When messages are accessed with POP&amp;apos; is set to &amp;quot;keep Gmail's copy in the Inbox&amp;quot;. &lt;em&gt;This is always a safe bet to keep your emails in the Gmail's inbox and not have them deleted when you retrieve them from Gmail's POP3 server&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Now click &amp;apos;Save Changes&amp;apos; button to save the changes.&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;&lt;b&gt;Running the Pop3Client.aspx Page&lt;/b&gt;&lt;br /&gt;
After placing &amp;quot;Pop3.cs&amp;quot; in the &lt;code&gt;/App_Code&lt;/code&gt; sub-folder and &lt;code&gt;Pop3Client.aspx&lt;/code&gt; in the &lt;code&gt;/&lt;/code&gt; folder of my ASP.NET web application, I ran the &lt;code&gt;Pop3Client.aspx&lt;/code&gt; page and got following result:&lt;/p&gt;

&lt;div align="center"&gt;
&lt;img src="http://www.stardeveloper.com/images/articles/2009071001_pop3-listing-emails.gif" width="600" height="235" border="0" alt="Listing emails" /&gt;
&lt;/div&gt;

&lt;p&gt;I hope you were also able to successfully connect to your email's mailbox on the remote server and were able to view the list of emails in it.&lt;/p&gt;

&lt;div align="center" style="background-color: #F7F7F7;"&gt;&lt;b&gt;Note:&lt;/b&gt; It is recommended that you study the code in full to understand how we are connecting to, sending and receiving data over the network. If your POP3 server doesn't support secure access over SSL, you should set the &lt;code&gt;secure&lt;/code&gt; argument in the constructor of &lt;code&gt;Pop3Client&lt;/code&gt; class to &lt;code&gt;false&lt;/code&gt;.&lt;/div&gt;

&lt;p&gt;&lt;b&gt;Summary&lt;/b&gt;&lt;br /&gt;
In this tutorial, we developed code to connect to Gmail's secure POP3 server using SSL. We learned about &lt;code&gt;TcpClient&lt;/code&gt;, &lt;code&gt;NetworkStream&lt;/code&gt;, &lt;code&gt;SslStream&lt;/code&gt;, &lt;code&gt;StreamWriter&lt;/code&gt; and &lt;code&gt;StreamReader&lt;/code&gt; classes. Using these classes we created our own set of top level classes to make the task of communicating with the server, easier. An ASP.NET page in the end, using the code that we developed, successfully displayed the list of emails retrieved from the server.&lt;/p&gt;

&lt;p&gt;In the next tutorial (&lt;a href="http://www.stardeveloper.com/articles/display.html?article=2009071001&amp;page=1"&gt;Displaying Emails from Mailbox on Gmail using POP3 and ASP.NET&lt;/a&gt;), we will create an ASP.NET page that will retrieve the actual email from the POP3 server and display it to the user.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.stardeveloper.com/~ff/StardevelopercomArticleHeadlines?a=ZHb7g3uF9Sk:Hi98PiesArA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/StardevelopercomArticleHeadlines?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.stardeveloper.com/~ff/StardevelopercomArticleHeadlines?a=ZHb7g3uF9Sk:Hi98PiesArA:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/StardevelopercomArticleHeadlines?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/StardevelopercomArticleHeadlines/~4/ZHb7g3uF9Sk" height="1" width="1"/&gt;</description>
<guid isPermaLink="false"><![CDATA[http://www.stardeveloper.com/articles/display.html?article=2009070801&page=1]]></guid>
<author>Faisal Khan</author>
<pubDate>Wed, 08 Jul 2009 10:13:00 GMT</pubDate>
<atom:link href="http://feeds.stardeveloper.com/StardevelopercomArticleHeadlines" rel="self" type="application/rss+xml" /><feedburner:origLink>http://www.stardeveloper.com/articles/display.html?article=2009070801&amp;page=1</feedburner:origLink></item>
<item>
<title>Displaying Twitter Updates in a Page by Page fashion with ASP.NET</title>
<link>http://feeds.stardeveloper.com/~r/StardevelopercomArticleHeadlines/~3/WZHBIju0wR0/display.html</link>
<description>&lt;p&gt;&lt;b&gt;Introduction&lt;/b&gt;&lt;br /&gt;
In this tutorial, we will develop a technique to retrieve and display a page full of Twitter updates to the user, giving him the ability to move to the next page. The user will be able to browse all the pages using &amp;apos;Previous Page&amp;apos; and &amp;apos;Next Page&amp;apos; links. Our technique will be highly efficient as we will be retrieving only enough number of Twitter updates from a given screen name, to display on a single page. Only when the user browses to the next page will another set of Twitter updates be retrieved. At the same time we will cache the results, page by page, giving seamless and smooth performance to the end user.&lt;/p&gt;

&lt;p&gt;The code in this tutorial makes use of the code we developed in the previous tutorial: &lt;a href="http://www.stardeveloper.com/articles/display.html?article=2009061701&amp;page=1"&gt;Retrieving Twitter Updates with ASP.NET&lt;/a&gt;. We will only be updating &lt;code&gt;TwitterClient.cs&lt;/code&gt; a little bit to enable retrieval of Twitter updates page by page. Rest of the files will remain the same. We will develop an ASP.NET page to demonstrate the technique.&lt;/p&gt;

&lt;p&gt;I advise that you read this series of tutorials from the beginning and create/place the files as advised in the previous tutorial.&lt;/p&gt;

&lt;p&gt;This tutorial is 3rd in the series of tutorials regarding Twitter and ASP.NET:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://www.stardeveloper.com/articles/display.html?article=2009061401&amp;page=1"&gt;Introduction to Twitter for ASP.NET Developers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.stardeveloper.com/articles/display.html?article=2009061701&amp;page=1"&gt;Retrieving Twitter Updates with ASP.NET&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Displaying Twitter Updates in a Page by Page fashion with ASP.NET&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;b&gt;Demonstration of Twitter Updates being Displayed Page by Page&lt;/b&gt;&lt;br /&gt;
In this tutorial, we will develop an ASP.NET page that retrieves 5 status updates for a given screen name and displays them on a page. When 'Next Page' link is clicked, next 5 status updates are retrieved and displayed to the user.&lt;/p&gt;

&lt;div align="center" style="background-color: #F7F7F7;"&gt;&lt;b&gt;Note:&lt;/b&gt; 5 is an arbitrary number. You can modify the code to display any number of status updates per page.&lt;/div&gt;

&lt;p&gt;Following screen shots show the ASP.NET page displaying Twitter status updates in a page by page fashion:&lt;/p&gt;

&lt;div align="center" style="margin-bottom: 20px"&gt;
&lt;img src="http://www.stardeveloper.com/images/articles/2009062001_stardeveloper-updates-page-1.gif" width="400" height="365" border="0" alt="Displaying Twitter Updates Page by Page" /&gt;
&lt;/div&gt;

&lt;div align="center"&gt;
&lt;img src="http://www.stardeveloper.com/images/articles/2009062001_stardeveloper-updates-page-2.gif" width="400" height="222" border="0" alt="Displaying Twitter Updates Page by Page" /&gt;
&lt;/div&gt;

&lt;p&gt;Let us now go ahead and develop the necessary code.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Developing the Code&lt;/b&gt;&lt;br /&gt;
We need to update &lt;code&gt;TwitterClient.cs&lt;/code&gt; file to accomodate the retrieval of Twitter status updates  page by page.&lt;/p&gt;

&lt;div align="center" style="background-color: #F7F7F7;"&gt;&lt;b&gt;Note:&lt;/b&gt; It is absolutely necessary to create and place the files as described in &lt;a href="http://www.stardeveloper.com/articles/display.html?article=2009061701&amp;page=1"&gt;Retrieving Twitter Updates with ASP.NET&lt;/a&gt; tutorial. Without which you will not be able to make the changes as described below.&lt;/div&gt;

&lt;p&gt;&lt;b&gt;Updated TwitterClient.cs&lt;/b&gt;&lt;br /&gt;
You should replace the code in &lt;code&gt;TwitterClient.cs&lt;/code&gt; with the code given below. The updated sections of the code have been highlighted.&lt;/p&gt;

&lt;pre&gt;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using System.Xml;
using Stardeveloper.Twitter;

namespace Stardeveloper.Twitter
{
	public class TwitterClient
	{
	public const string StatusesUserTimelineStr =
		&amp;quot;http://twitter.com/statuses/user_timeline.xml?&amp;quot; +
		&amp;quot;screen_name={0}&amp;amp;count={1}&amp;amp;page={2}&amp;quot;;

	public TwitterClient()
	{
	}

	protected virtual string FetchXmlFromUrl(string url)
	{
		using (WebClient client = new WebClient())
		using (Stream s = client.OpenRead(url))
		using (StreamReader sr = new StreamReader(s))
		{
			return sr.ReadToEnd();
		}
	}&lt;/pre&gt;

&lt;p&gt;The code continues on the next page.&lt;/p&gt;&lt;pre&gt;protected virtual List&amp;lt;Status&amp;gt;
		CreateStatusObjectsFromXml(string xml, int count)
	{
		List&amp;lt;Status&amp;gt; statuses = new List&amp;lt;Status&amp;gt;(count);

		XmlDocument xmldoc = new XmlDocument();
		xmldoc.LoadXml(xml);

		foreach (XmlNode status in xmldoc.DocumentElement)
		{
		// created_at
		string value = status.SelectSingleNode(&amp;quot;created_at&amp;quot;).InnerXml;
		DateTime statusCreatedAt = ConvertStrToUtcDateTime(value);

		// id
		value = status.SelectSingleNode(&amp;quot;id&amp;quot;).InnerXml;
		long statusId = Convert.ToInt64(value);

		// text
		string text = status.SelectSingleNode(&amp;quot;text&amp;quot;).InnerXml;

		// source
		string source = status.SelectSingleNode(&amp;quot;source&amp;quot;).InnerXml;

		// truncated
		value = status.SelectSingleNode(&amp;quot;truncated&amp;quot;).InnerXml;
		bool truncated = Convert.ToBoolean(value);

		// in_reply_to_status_id
		value = status.SelectSingleNode(&amp;quot;in_reply_to_status_id&amp;quot;).InnerXml;
		long inReplyToStatusId = value != &amp;quot;&amp;quot; ? Convert.ToInt64(value) : 0;

		// in_reply_to_user_id
		value = status.SelectSingleNode(&amp;quot;in_reply_to_user_id&amp;quot;).InnerXml;
		long inReplyToUserId = value != &amp;quot;&amp;quot; ? Convert.ToInt64(value) : 0;

		// favorited
		value = status.SelectSingleNode(&amp;quot;favorited&amp;quot;).InnerXml;
		bool favorited = Convert.ToBoolean(value);

		// in_reply_to_screen_name
		string inReplyToScreenName =
			status.SelectSingleNode(&amp;quot;in_reply_to_screen_name&amp;quot;).InnerXml;

		/* Getting into user element */
		XmlNode user = status.SelectSingleNode(&amp;quot;user&amp;quot;);

		// id
		value = user.SelectSingleNode(&amp;quot;id&amp;quot;).InnerXml;
		long userId = Convert.ToInt64(value);

		// name
		string name = user.SelectSingleNode(&amp;quot;name&amp;quot;).InnerXml;

		// screen_name
		string screenName = user.SelectSingleNode(&amp;quot;screen_name&amp;quot;).InnerXml;

		// location
		string location = user.SelectSingleNode(&amp;quot;location&amp;quot;).InnerXml;

		// description
		string description = user.SelectSingleNode(&amp;quot;description&amp;quot;).InnerXml;

		// profile_image_url
		string profileImageUrl =
			user.SelectSingleNode(&amp;quot;profile_image_url&amp;quot;).InnerXml;

		// url
		string url = user.SelectSingleNode(&amp;quot;url&amp;quot;).InnerXml;

		// protected
		value = user.SelectSingleNode(&amp;quot;protected&amp;quot;).InnerXml;
		bool protectedstr = Convert.ToBoolean(value);

		// followers_count
		value = user.SelectSingleNode(&amp;quot;followers_count&amp;quot;).InnerXml;
		long followersCount = Convert.ToInt64(value);

		// profile_background_color
		string profileBackgroundColor =
			user.SelectSingleNode(&amp;quot;profile_background_color&amp;quot;).InnerXml;

		// profile_text_color
		string profileTextColor =
			user.SelectSingleNode(&amp;quot;profile_text_color&amp;quot;).InnerXml;

		// profile_link_color
		string profileLinkColor =
			user.SelectSingleNode(&amp;quot;profile_link_color&amp;quot;).InnerXml;

		// profile_sidebar_fill_color
		string profileSidebarFillColor =
			user.SelectSingleNode(&amp;quot;profile_sidebar_fill_color&amp;quot;)
				.InnerXml;

		// profile_sidebar_border_color
		string profileSidebarBorderColor =
			user.SelectSingleNode(&amp;quot;profile_sidebar_border_color&amp;quot;)
				.InnerXml;

		// friends_count
		value = user.SelectSingleNode(&amp;quot;friends_count&amp;quot;).InnerXml;
		long friendsCount = Convert.ToInt64(value);

		// created_at
		value = user.SelectSingleNode(&amp;quot;created_at&amp;quot;).InnerXml;
		DateTime userCreatedAt = TwitterClient.ConvertStrToUtcDateTime(value);

		// favourites_count
		value = user.SelectSingleNode(&amp;quot;favourites_count&amp;quot;).InnerXml;
		long favouritesCount = Convert.ToInt64(value);

		// utc_offset
		value = user.SelectSingleNode(&amp;quot;utc_offset&amp;quot;).InnerXml;
		int utcOffset = Convert.ToInt32(value);

		// time_zone
		string timeZone = user.SelectSingleNode(&amp;quot;time_zone&amp;quot;).InnerXml;

		// profile_background_image_url
		string profileBackgroundImageUrl =
			user.SelectSingleNode(&amp;quot;profile_background_image_url&amp;quot;).InnerXml;

		// profile_background_tile
		value = user.SelectSingleNode(&amp;quot;profile_background_tile&amp;quot;).InnerXml;
		bool profileBackgroundTile = Convert.ToBoolean(value);

		// statuses_count
		value = user.SelectSingleNode(&amp;quot;statuses_count&amp;quot;).InnerXml;
		long statusesCount = Convert.ToInt64(value);

		// notifications
		string notifications = user.SelectSingleNode(&amp;quot;notifications&amp;quot;).InnerXml;

		// following
		string following = user.SelectSingleNode(&amp;quot;following&amp;quot;).InnerXml;

		/* Creating User object */
		User userobj = new User(userId, name, screenName, location,
			description, profileImageUrl, url, protectedstr,
			followersCount, profileBackgroundColor, profileTextColor,
			profileLinkColor, profileSidebarFillColor,
			profileSidebarBorderColor, friendsCount, userCreatedAt,
			favouritesCount, utcOffset, timeZone,
			profileBackgroundImageUrl, profileBackgroundTile,
			statusesCount, notifications, following);

		Status statusobj = new Status(statusCreatedAt, statusId,
			text, source, truncated, inReplyToStatusId, inReplyToUserId,
			favorited, inReplyToScreenName, userobj);

		statuses.Add(statusobj);
		}

		return statuses;
	}

	public Status GetLatestStatusUpdate(string screenName)
	{
		List&amp;lt;Status&amp;gt; statuses = GetStatusUpdates(screenName, 1);

		return statuses[0];
	}

	public List&amp;lt;Status&amp;gt; GetStatusUpdates(string screenName, int count)
	{
		return GetStatusUpdates(screenName, count, 1);
	}

	public List&amp;lt;Status&amp;gt; GetStatusUpdates(string screenName, int count,
		int page)
	{
		string url = String.Format(StatusesUserTimelineStr,
			screenName, count, page);
		string xml = FetchXmlFromUrl(url);

		return CreateStatusObjectsFromXml(xml, count);
	}

	public static DateTime ConvertStrToUtcDateTime(string str)
	{
		string[] arr = str.Split(&amp;apos; &amp;apos;);

		int day, month, year, hour, min, sec;

		switch (arr[1])
		{
			case &amp;quot;Jan&amp;quot;:
				month = 1;
				break;
			case &amp;quot;Feb&amp;quot;:
				month = 2;
				break;
			case &amp;quot;Mar&amp;quot;:
				month = 3;
				break;
			case &amp;quot;Apr&amp;quot;:
				month = 4;
				break;
			case &amp;quot;May&amp;quot;:
				month = 5;
				break;
			case &amp;quot;Jun&amp;quot;:
				month = 6;
				break;
			case &amp;quot;Jul&amp;quot;:
				month = 7;
				break;
			case &amp;quot;Aug&amp;quot;:
				month = 8;
				break;
			case &amp;quot;Sep&amp;quot;:
				month = 9;
				break;
			case &amp;quot;Oct&amp;quot;:
				month = 10;
				break;
			case &amp;quot;Nov&amp;quot;:
				month = 11;
				break;
			case &amp;quot;Dec&amp;quot;:
				month = 12;
				break;
			default:
				throw new FormatException(&amp;quot;Unknown month.&amp;quot;);
		}

		day = Convert.ToInt32(arr[2]);

		string[] arr1 = arr[3].Split(&amp;apos;:&amp;apos;);

		hour = Convert.ToInt32(arr1[0]);
		min = Convert.ToInt32(arr1[1]);
		sec = Convert.ToInt32(arr1[2]);

		string offsetSign = arr[4].Substring(0, 1);
		int offsetHours = Convert.ToInt32(arr[4].Substring(1, 2));
		int offsetMinutes = Convert.ToInt32(arr[4].Substring(3, 2));

		year = Convert.ToInt32(arr[5]);

		DateTime dt = new DateTime(year, month, day, hour, min, sec);

		if (offsetSign == &amp;quot;+&amp;quot;)
		{
			dt.AddHours(offsetHours);
			dt.AddMinutes(offsetMinutes);
		}
		else if (offsetSign == &amp;quot;-&amp;quot;)
		{
			dt.AddHours(-offsetHours);
			dt.AddMinutes(-offsetMinutes);
		}

		return dt;
	}
	}
}&lt;/pre&gt;

&lt;p&gt;Code is explained on the next page.&lt;/p&gt;&lt;p&gt;&lt;b&gt;Explanation&lt;/b&gt;&lt;br /&gt;
The URL to retrieve Twitter status updates remains the same but we add an extra querystring parameter to tell Twitter which page we want to retrieve. The &lt;code&gt;screen_name&lt;/code&gt; should be set to the screen name of the user whose status updates we want to retrieve. The &lt;code&gt;count&lt;/code&gt; parameter should be set to a numeric value of number of status updates you want to show per page. The &lt;code&gt;page&lt;/code&gt; parameter should be set to a numeric value of the page whose status updates you want to retrieve, beginning from 1. You don't have to manually set these values. It is only for you to understand what is going on behind the scenes.&lt;/p&gt;

&lt;pre&gt;
public const string StatusesUserTimelineStr =
	&amp;quot;http://twitter.com/statuses/user_timeline.xml?&amp;quot; +
	&amp;quot;screen_name={0}&amp;amp;count={1}&amp;amp;page={2}&amp;quot;;&lt;/pre&gt;

&lt;p&gt;Next we add another &lt;code&gt;GetStatusUpdates()&lt;/code&gt; method with the extra option of specifying the page you want to retrieve status updates from.&lt;/p&gt;

&lt;pre&gt;
public List&amp;lt;Status&amp;gt; GetStatusUpdates(string screenName, int count,
	int page)
{
	string url = String.Format(StatusesUserTimelineStr,
		screenName, count, page);
	string xml = FetchXmlFromUrl(url);

	return CreateStatusObjectsFromXml(xml, count);
}&lt;/pre&gt;

&lt;p&gt;This is it as far as the changes in &lt;code&gt;TwitterClient.cs&lt;/code&gt; are concerned.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;TwitterAllUpdates.aspx&lt;/b&gt;&lt;br /&gt;
The logic to pull the the right page and display the status updates properly is handled by this ASP.NET page. Open notepad and copy following code in it and then save it as &amp;quot;TwitterAllUpdates.aspx&amp;quot; in the main folder of your ASP.NET web application:&lt;/p&gt;

&lt;pre&gt;
&amp;lt;%@ Page Language=&amp;quot;C#&amp;quot; %&amp;gt;

&amp;lt;%@ OutputCache VaryByParam=&amp;quot;page&amp;quot; Duration=&amp;quot;1200&amp;quot; %&amp;gt;

&amp;lt;%@ Import Namespace=&amp;quot;System.Collections.Generic&amp;quot; %&amp;gt;
&amp;lt;%@ Import Namespace=&amp;quot;Stardeveloper.Twitter&amp;quot; %&amp;gt;

&amp;lt;script runat=&amp;quot;server&amp;quot;&amp;gt;
public const int StatusUpdatesPerPage = 5;
public const string ScreenName = &amp;quot;Stardeveloper&amp;quot;;
public const string LinkText =
	&amp;quot;&amp;lt;a href=\&amp;quot;TwitterAllUpdates.aspx?page={0}\&amp;quot;&amp;gt;{1}&amp;lt;/a&amp;gt;&amp;quot;;

protected void Page_Load(object source, EventArgs e)
{
	/* Setting current page and total pages */
	int page = 1;
	int totalPages = -1;

	if (Request.QueryString[&amp;quot;page&amp;quot;] == null)
		Response.Redirect(&amp;quot;TwitterAllUpdates.aspx?page=1&amp;quot;);
	else
		page = Convert.ToInt32(Request.QueryString[&amp;quot;page&amp;quot;]);
	
	/* Retrieving status updates in real-time */
	TwitterClient client = new TwitterClient();
	List&amp;lt;Status&amp;gt; statuses = client.GetStatusUpdates(ScreenName,
		StatusUpdatesPerPage, page);

	foreach (Status status in statuses)
	{
		/* Appending each status to existing table */
		TableCell statusCell = new TableCell();
		statusCell.ColumnSpan = 2;
		statusCell.CssClass = &amp;quot;status-updates-table-cell&amp;quot;;

		StringBuilder statusBuilder = new StringBuilder();
		statusBuilder.Append(status.FormattedText);
		statusBuilder.Append(&amp;quot;&amp;lt;div class=\&amp;quot;status-datetime\&amp;quot;&amp;gt;&amp;quot;);
		statusBuilder.Append(status.CreatedAt.ToShortDateString());
		statusBuilder.Append(&amp;quot; &amp;quot;);
		statusBuilder.Append(status.CreatedAt.ToShortTimeString());
		statusBuilder.Append(&amp;quot;&amp;lt;/div&amp;gt;&amp;quot;);
		
		statusCell.Text = statusBuilder.ToString();

		TableRow statusRow = new TableRow();
		statusRow.Cells.Add(statusCell);

		StatusUpdatesTable.Rows.Add(statusRow);

		/* Computing total possible pages */
		if (totalPages == -1)
		{
			int statusesCount =
				Convert.ToInt32(status.User.StatusesCount);
			int mod = statusesCount % StatusUpdatesPerPage;
			
			if (mod == 0)
				totalPages = statusesCount / StatusUpdatesPerPage;
			else
				totalPages = ((statusesCount - mod) /
					StatusUpdatesPerPage) + 1;
		}
	}

	/* Creating links to previous and next pages */
	if (totalPages &amp;gt; 1)
	{
		TableCell prevPageCell = new TableCell();
		TableCell nextPageCell = new TableCell();

		prevPageCell.CssClass = &amp;quot;status-updates-table-footer&amp;quot;;
		nextPageCell.CssClass = &amp;quot;status-updates-table-footer&amp;quot;;
		nextPageCell.Style[&amp;quot;text-align&amp;quot;] = &amp;quot;right&amp;quot;;

		if (page &amp;gt; 1)
			prevPageCell.Text = String.Format(LinkText, page - 1,
				&amp;quot;Previous Page&amp;quot;);

		if (page &amp;gt; 0 &amp;amp;&amp;amp; page &amp;lt; totalPages)
			nextPageCell.Text = String.Format(LinkText, page + 1,
				&amp;quot;Next Page&amp;quot;);

		TableFooterRow footerRow = new TableFooterRow();
		footerRow.Cells.Add(prevPageCell);
		footerRow.Cells.Add(nextPageCell);

		StatusUpdatesTable.Rows.Add(footerRow);
	}

	/* Setting some values to display to the user */
	ScreenNameLiteral.Text = ScreenName;
	PageLiteral.Text = Convert.ToString(page);
	TotalPagesLiteral.Text = Convert.ToString(totalPages);
}
&amp;lt;/script&amp;gt;

&amp;lt;!DOCTYPE html PUBLIC &amp;quot;-//W3C//DTD XHTML 1.0 Transitional//EN&amp;quot;
	&amp;quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&amp;quot;&amp;gt;

&amp;lt;html xmlns=&amp;quot;http://www.w3.org/1999/xhtml&amp;quot;&amp;gt;
&amp;lt;head runat=&amp;quot;server&amp;quot;&amp;gt;
    &amp;lt;title&amp;gt;&amp;lt;/title&amp;gt;
    &amp;lt;style type=&amp;quot;text/css&amp;quot;&amp;gt;
		.status-updates-table { width: 400px; border: solid 1px #444444; }
		.status-updates-table-header { font-family: &amp;quot;Trebuchet MS&amp;quot;;
			font-size: 9pt; background-color: #0099B9; color: white;
			border: solid 1px #444444; }
		.status-updates-table-cell { font-family: &amp;quot;Georgia&amp;quot;;
			font-size: 9pt; border: solid 1px #666666; padding: 6px; }
		.status-updates-table-footer { border: solid 1px #666666;
			padding: 3px; width: 50%; }
		.status-datetime { float: right; color: #666666; }
		
		a { font-family: &amp;quot;Lucida Sans Unicode&amp;quot;,
			&amp;quot;Trebuchet MS&amp;quot;; font-size: 9pt;
			color: #005B7F; }
		a:hover { color:red; }
    &amp;lt;/style&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
    &amp;lt;form id=&amp;quot;form1&amp;quot; runat=&amp;quot;server&amp;quot;&amp;gt;
	&amp;lt;asp:Table ID=&amp;quot;StatusUpdatesTable&amp;quot;
		CssClass=&amp;quot;status-updates-table&amp;quot; runat=&amp;quot;server&amp;quot;&amp;gt;
	&amp;lt;asp:TableHeaderRow&amp;gt;
		&amp;lt;asp:TableHeaderCell CssClass=&amp;quot;status-updates-table-header&amp;quot;
		ColumnSpan=&amp;quot;2&amp;quot;&amp;gt;
		&amp;lt;asp:Literal ID=&amp;quot;ScreenNameLiteral&amp;quot; runat=&amp;quot;server&amp;quot; /&amp;gt; Updates (page 
		&amp;lt;asp:Literal ID=&amp;quot;PageLiteral&amp;quot; runat=&amp;quot;server&amp;quot; /&amp;gt; of 
		&amp;lt;asp:Literal ID=&amp;quot;TotalPagesLiteral&amp;quot; runat=&amp;quot;server&amp;quot; /&amp;gt;)
		&amp;lt;/asp:TableHeaderCell&amp;gt;
	&amp;lt;/asp:TableHeaderRow&amp;gt;
	&amp;lt;/asp:Table&amp;gt;
    &amp;lt;/form&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/pre&gt;

&lt;p&gt;&lt;b&gt;Explanation&lt;/b&gt;&lt;br /&gt;
The first &lt;code&gt;Page&lt;/code&gt; level directive tells ASP.NET compiler that the default language in this page is going to be C#.&lt;/p&gt;

&lt;pre&gt;
&amp;lt;%@ Page Language=&amp;quot;C#&amp;quot; %&amp;gt;&lt;/pre&gt;

&lt;p&gt;Next, an &lt;code&gt;OutputCache&lt;/code&gt; directive tells the ASP.NET runtime to cache the output of this page for 20 minutes (20 min x 60 sec = 1200 sec). The &lt;code&gt;VaryByParam&lt;/code&gt; attribute is set to &amp;quot;page&amp;quot; which makes sure that a new copy of the output of this page will be cached for each variation of &amp;quot;page&amp;quot; querystring parameter.&lt;/p&gt;

&lt;pre&gt;
&amp;lt;%@ OutputCache VaryByParam=&amp;quot;page&amp;quot; Duration=&amp;quot;1200&amp;quot; %&amp;gt;&lt;/pre&gt;&lt;p&gt;Necessary namespaces are imported. &lt;code&gt;System.Collections.Generic&lt;/code&gt; namespace is necessary because we want to use generic &lt;code&gt;List&amp;lt;T&amp;gt;&lt;/code&gt; class. &lt;code&gt;Stardeveloper.Twitter&lt;/code&gt; namespace is necessary because we want to make use of &lt;code&gt;TwitterClient&lt;/code&gt;, &lt;code&gt;Status&lt;/code&gt;, and &lt;code&gt;User&lt;/code&gt; classes, we developed earlier.&lt;/p&gt;

&lt;pre&gt;
&amp;lt;%@ Import Namespace=&amp;quot;System.Collections.Generic&amp;quot; %&amp;gt;
&amp;lt;%@ Import Namespace=&amp;quot;Stardeveloper.Twitter&amp;quot; %&amp;gt;&lt;/pre&gt;

&lt;p&gt;A server-side script tag tells the ASP.NET compiler that this segment is going to contain server-side code.&lt;/p&gt;

&lt;pre&gt;
&amp;lt;script runat=&amp;quot;server&amp;quot;&amp;gt;
	...
&amp;lt;/script&amp;gt;&lt;/pre&gt;

&lt;p&gt;We define 3 page level constant variables. &lt;code&gt;StatusUpdatesPerPage&lt;/code&gt; variable is set to the number of status updates we want to display per page. You can change this value to suit the need of your web application. &lt;code&gt;ScreenName&lt;/code&gt; variable is set to the screen name of the user whose status updates you want to retrieve from Twitter. &lt;code&gt;LinkText&lt;/code&gt; contains string which contains placeholders which will be set by the code later. This variable will be used to create &amp;apos;Previous Page&amp;apos; and &amp;apos;Next Page&amp;apos; links, in the table, under the status updates, later.&lt;/p&gt;

&lt;pre&gt;
public const int StatusUpdatesPerPage = 5;
public const string ScreenName = &amp;quot;Stardeveloper&amp;quot;;
public const string LinkText =
	&amp;quot;&amp;lt;a href=\&amp;quot;TwitterAllUpdates.aspx?page={0}\&amp;quot;&amp;gt;{1}&amp;lt;/a&amp;gt;&amp;quot;;&lt;/pre&gt;

&lt;p&gt;Next, we place all of our important code in the &lt;code&gt;Page_Load()&lt;/code&gt; method.&lt;/p&gt;

&lt;pre&gt;
protected void Page_Load(object source, EventArgs e)
{
	...
}&lt;/pre&gt;

&lt;p&gt;Within the &lt;code&gt;Page_Load()&lt;/code&gt; method, we start by declaring two important variables. &lt;code&gt;page&lt;/code&gt; should be set to the page whose status updates we want to retrieve from Twitter and display to the user. &lt;code&gt;totalPages&lt;/code&gt; should be set to the total number of pages that are available for this screen name. If a user has 100 status updates at Twitter and we want to show 20 updates per page, then &lt;code&gt;totalPages&lt;/code&gt; should be set to 5.&lt;/p&gt;

&lt;p&gt;If the querystring parameter, &amp;quot;page&amp;quot;, is not set, the we set the querystring parameter and redirect the user to the same page. Otherwise, we fetch and set the &lt;code&gt;page&lt;/code&gt; variable's value to it.&lt;/p&gt;

&lt;pre&gt;
/* Setting current page and total pages */
int page = 1;
int totalPages = -1;

if (Request.QueryString[&amp;quot;page&amp;quot;] == null)
	Response.Redirect(&amp;quot;TwitterAllUpdates.aspx?page=1&amp;quot;);
else
	page = Convert.ToInt32(Request.QueryString[&amp;quot;page&amp;quot;]);&lt;/pre&gt;

&lt;p&gt;We then create &lt;code&gt;TwitterClient&lt;/code&gt; object and retrieve given status updates for a given page from Twitter. Once we have the list of status updates as &lt;code&gt;Status&lt;/code&gt; objects, we iterate through them, one by one, and populate our HTML table with its values.&lt;/p&gt;

&lt;pre&gt;
/* Retrieving status updates in real-time */
TwitterClient client = new TwitterClient();
List&amp;lt;Status&amp;gt; statuses = client.GetStatusUpdates(ScreenName,
	StatusUpdatesPerPage, page);

foreach (Status status in statuses)
{
	...
}&lt;/pre&gt;

&lt;p&gt;For each &lt;code&gt;Status&lt;/code&gt; object, we fetch formatted text by accessing the &lt;code&gt;Status.FormattedText&lt;/code&gt; property and append to it date &amp;amp; time of the status update. This text is then appended as an HTML row to an HTML table we have already placed as a user control in our ASP.NET page.&lt;/p&gt;

&lt;pre&gt;
/* Appending each status to existing table */
TableCell statusCell = new TableCell();
statusCell.ColumnSpan = 2;
statusCell.CssClass = &amp;quot;status-updates-table-cell&amp;quot;;

StringBuilder statusBuilder = new StringBuilder();
statusBuilder.Append(status.FormattedText);
statusBuilder.Append(&amp;quot;&amp;lt;div class=\&amp;quot;status-datetime\&amp;quot;&amp;gt;&amp;quot;);
statusBuilder.Append(status.CreatedAt.ToShortDateString());
statusBuilder.Append(&amp;quot; &amp;quot;);
statusBuilder.Append(status.CreatedAt.ToShortTimeString());
statusBuilder.Append(&amp;quot;&amp;lt;/div&amp;gt;&amp;quot;);

statusCell.Text = statusBuilder.ToString();

TableRow statusRow = new TableRow();
statusRow.Cells.Add(statusCell);

StatusUpdatesTable.Rows.Add(statusRow);&lt;/pre&gt;

&lt;p&gt;Last bit of code checks and sets the &lt;code&gt;totalPages&lt;/code&gt; variable to total number of pages for this screen name using given status updates per page.&lt;/p&gt;

&lt;pre&gt;
/* Computing total possible pages */
if (totalPages == -1)
{
	int statusesCount =
		Convert.ToInt32(status.User.StatusesCount);
	int mod = statusesCount % StatusUpdatesPerPage;
	
	if (mod == 0)
		totalPages = statusesCount / StatusUpdatesPerPage;
	else
		totalPages = ((statusesCount - mod) /
			StatusUpdatesPerPage) + 1;
}&lt;/pre&gt;

&lt;p&gt;Once all &lt;code&gt;Status&lt;/code&gt; objects' formatted text has been appended to the HTML table in our ASP.NET page, we append &amp;apos;Previous Page&amp;apos; and &amp;apos;Next Page&amp;apos; links to the HTML table using the logic given below:&lt;/p&gt;

&lt;pre&gt;
/* Creating links to previous and next pages */
if (totalPages &amp;gt; 1)
{
	TableCell prevPageCell = new TableCell();
	TableCell nextPageCell = new TableCell();

	prevPageCell.CssClass = &amp;quot;status-updates-table-footer&amp;quot;;
	nextPageCell.CssClass = &amp;quot;status-updates-table-footer&amp;quot;;
	nextPageCell.Style[&amp;quot;text-align&amp;quot;] = &amp;quot;right&amp;quot;;

	if (page &amp;gt; 1)
		prevPageCell.Text = String.Format(LinkText, page - 1,
			&amp;quot;Previous Page&amp;quot;);

	if (page &amp;gt; 0 &amp;amp;&amp;amp; page &amp;lt; totalPages)
		nextPageCell.Text = String.Format(LinkText, page + 1,
			&amp;quot;Next Page&amp;quot;);

	TableFooterRow footerRow = new TableFooterRow();
	footerRow.Cells.Add(prevPageCell);
	footerRow.Cells.Add(nextPageCell);

	StatusUpdatesTable.Rows.Add(footerRow);
}&lt;/pre&gt;

&lt;p&gt;Lastly, 3 &lt;code&gt;Literal&lt;/code&gt; controls' values are set. These values will be displayed to the user.&lt;/p&gt;

&lt;pre&gt;
/* Setting some values to display to the user */
ScreenNameLiteral.Text = ScreenName;
PageLiteral.Text = Convert.ToString(page);
TotalPagesLiteral.Text = Convert.ToString(totalPages);&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;StatusUpdatesTable&lt;/code&gt; is the id of the HTML table that will display the Twitter status updates to the user in our ASP.NET page.&lt;/p&gt;

&lt;pre&gt;
&amp;lt;asp:Table ID=&amp;quot;StatusUpdatesTable&amp;quot;
	CssClass=&amp;quot;status-updates-table&amp;quot; runat=&amp;quot;server&amp;quot;&amp;gt;
&amp;lt;asp:TableHeaderRow&amp;gt;
	&amp;lt;asp:TableHeaderCell CssClass=&amp;quot;status-updates-table-header&amp;quot;
	ColumnSpan=&amp;quot;2&amp;quot;&amp;gt;
	&amp;lt;asp:Literal ID=&amp;quot;ScreenNameLiteral&amp;quot; runat=&amp;quot;server&amp;quot; /&amp;gt; Updates (page 
	&amp;lt;asp:Literal ID=&amp;quot;PageLiteral&amp;quot; runat=&amp;quot;server&amp;quot; /&amp;gt; of 
	&amp;lt;asp:Literal ID=&amp;quot;TotalPagesLiteral&amp;quot; runat=&amp;quot;server&amp;quot; /&amp;gt;)
	&amp;lt;/asp:TableHeaderCell&amp;gt;
&amp;lt;/asp:TableHeaderRow&amp;gt;
&amp;lt;/asp:Table&amp;gt;&lt;/pre&gt;

&lt;p&gt;When this ASP.NET page was run on my computer, it produced following output:&lt;/p&gt;

&lt;div align="center"&gt;
&lt;img src="http://www.stardeveloper.com/images/articles/2009062001_stardeveloper-updates-page-1.gif" width="400" height="365" border="0" alt="TwitterAllUpdates.aspx" /&gt;
&lt;/div&gt;

&lt;p&gt;&lt;b&gt;Summary&lt;/b&gt;&lt;br /&gt;
In this tutorial, we updated the code to add paging ability in our ASP.NET web application. We demonstrated the code by developing an ASP.NET page which displayed Twitter status updates, page by page.&lt;/p&gt;

&lt;p&gt;In the next tutorial, we will learn how to display &amp;quot;followers' count&amp;quot; on our website for a given screen name.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.stardeveloper.com/~ff/StardevelopercomArticleHeadlines?a=WZHBIju0wR0:2VjQwnoYvcs:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/StardevelopercomArticleHeadlines?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.stardeveloper.com/~ff/StardevelopercomArticleHeadlines?a=WZHBIju0wR0:2VjQwnoYvcs:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/StardevelopercomArticleHeadlines?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/StardevelopercomArticleHeadlines/~4/WZHBIju0wR0" height="1" width="1"/&gt;</description>
<guid isPermaLink="false"><![CDATA[http://www.stardeveloper.com/articles/display.html?article=2009062001&page=1]]></guid>
<author>Faisal Khan</author>
<pubDate>Sat, 20 Jun 2009 06:49:00 GMT</pubDate>
<atom:link href="http://feeds.stardeveloper.com/StardevelopercomArticleHeadlines" rel="self" type="application/rss+xml" /><feedburner:origLink>http://www.stardeveloper.com/articles/display.html?article=2009062001&amp;page=1</feedburner:origLink></item>
</channel>
</rss>
