<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://devlicio.us/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Rob Reynolds - The Fervent Coder : Tools, SidePOP</title><link>http://devlicio.us/blogs/rob_reynolds/archive/tags/Tools/SidePOP/default.aspx</link><description>Tags: Tools, SidePOP</description><dc:language>en</dc:language><generator>CommunityServer 2008.5 SP1 (Build: 31106.3070)</generator><item><title>Gems - Package Management For .NET</title><link>http://devlicio.us/blogs/rob_reynolds/archive/2010/07/15/gems-package-management-for-net.aspx</link><pubDate>Fri, 16 Jul 2010 04:27:00 GMT</pubDate><guid isPermaLink="false">40756a8b-6212-4073-9d98-6c26781577de:61091</guid><dc:creator>Rob Reynolds</dc:creator><slash:comments>18</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://devlicio.us/blogs/rob_reynolds/rsscomments.aspx?PostID=61091</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://devlicio.us/blogs/rob_reynolds/commentapi.aspx?PostID=61091</wfw:comment><comments>http://devlicio.us/blogs/rob_reynolds/archive/2010/07/15/gems-package-management-for-net.aspx#comments</comments><description>&lt;p&gt;The Ruby community has enjoyed a great user experience with a package management system they use called Gems. A gem is a package (or a library), compressed with some additional metadata, and can be either source files or binaries. Let&amp;rsquo;s focus on binary gems. We have the same concept in .NET (DLLs/EXEs). You may have references to other DLLs. When you want to update a reference you are using on a project, you may also need to update its dependencies as well. And so on and so forth. A package management project is meant to help make that easier. It&amp;rsquo;s actually really hard to explain what gems or package management without just showing you. So take a look here:&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &lt;a href="http://devlicio.us/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rob_5F00_reynolds/image_5F00_5AC297E8.png"&gt;&lt;img height="181" width="455" src="http://devlicio.us/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rob_5F00_reynolds/image_5F00_thumb_5F00_0456631C.png" alt="gem install sidepop - installed log4net - installed sidepop" border="0" title="gem install sidepop - installed log4net - installed sidepop" style="border-right-width:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I type:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;gem install sidepop&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And that&amp;rsquo;s it. It looks and sees that I have a dependency on log4net. Notice how it nicely just pulls down log4net version 1.2.10 as well? &lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;Background&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;I can count on one hand all of the package management projects that have been &lt;a target="_blank" href="http://strangelights.com/blog/archive/2010/05/16/1661.aspx"&gt;started&lt;/a&gt; &lt;a target="_blank" href="http://github.com/dagda1/horn_src"&gt;for&lt;/a&gt; &lt;a target="_blank" href="http://github.com/phatboyg/nu"&gt;.NET&lt;/a&gt;. &lt;a target="_blank" href="http://twitter.com/drusellers"&gt;Dru Sellers&lt;/a&gt;, &lt;a target="_blank" href="http://twitter.com/phatboyg"&gt;Chris Patterson&lt;/a&gt;, and I have talked about package management stuff from time to time. Dru and Chris have been a part of one project (&lt;a target="_blank" href="http://github.com/phatboyg/nu"&gt;Nu&lt;/a&gt;) that has been started several times to start to answer this question. We&amp;rsquo;ve participated on the mailing list for &lt;a target="_blank" href="http://groups.google.com/group/horn-development"&gt;HornGet&lt;/a&gt;. At one point I casually asked why we couldn&amp;rsquo;t just use gems. Other people out there have probably stated the same thing. But no one has really carried the idea forward. Until now.&lt;/p&gt;
&lt;p&gt;Yesterday Dru asked for a &lt;a target="_blank" href="http://code.google.com/p/uppercut/issues/detail?id=16"&gt;gem-ify&lt;/a&gt; feature for &lt;a target="_blank" href="http://projectuppercut.org"&gt;UppercuT&lt;/a&gt;. We started talking and looking at how easy it is to create a gem. Then we figured out how to make the &lt;a target="_blank" href="http://stackoverflow.com/questions/3250794/gems-with-net-applications-how-do-i-set-up-the-executables-so-they-run-without"&gt;executables&lt;/a&gt; piece work as well. This is where you can install a gem and then call the executable from the command line anywhere and get output. From the &lt;a target="_blank" href="http://groups.google.com/group/chucknorrisframework/browse_thread/thread/4f0c0deeadbd61d4"&gt;thread&lt;/a&gt; on &lt;a target="_blank" href="http://groups.google.com/group/chucknorrisframework/"&gt;ChuckNorris&lt;/a&gt; where we talked about this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Here is something you might find pretty interesting: &lt;a target="_blank" href="http://rubygems.org/gems/roundhouse"&gt;http://rubygems.org/gems/roundhouse&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href="http://rubygems.org/gems/roundhouse"&gt;&lt;/a&gt;If you have ruby installed, you can install roundhouse now from the command line:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;gem install roundhouse&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This gives you the opportunity to type this anywhere:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;rh &amp;lt;options&amp;gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;&lt;strong&gt;Why Should I Care?&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;If you work with Open Source, you know how much of a pain it can be to update your references. You update one library, say NHibernate, and find out that you also need to update your references to Castle. And possibly, you might then need to update your references to log4net. It can be a painful process. This is the start of answering that question.&lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;&lt;strong&gt;&lt;a href="http://devlicio.us/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rob_5F00_reynolds/image_5F00_18034CB0.png"&gt;&lt;img height="221" width="404" src="http://devlicio.us/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rob_5F00_reynolds/image_5F00_thumb_5F00_76A3A713.png" align="right" alt="Right now it&amp;#39;s starting to look like the answer for gems in .NET is just gems." border="0" title="Right now it&amp;#39;s starting to look like the answer for gems in .NET is just gems." style="border-right-width:0px;display:inline;border-top-width:0px;border-bottom-width:0px;margin-left:0px;border-left-width:0px;margin-right:0px;" /&gt;&lt;/a&gt;&lt;/strong&gt;Why Should I Get Excited?&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;It sounds like &lt;a target="_blank" href="http://twitter.com/jeremydmiller/statuses/18628012354"&gt;Jeremy Miller&lt;/a&gt; among others are getting excited about this. And why not? We&amp;rsquo;ve been trying to answer the gems question since Ruby made it so easy. &lt;/p&gt;
&lt;p&gt;The implications of this are awesome! I still haven&amp;rsquo;t fully grokked what we&amp;rsquo;ve just opened up.&amp;nbsp; But it&amp;rsquo;s huge! &lt;/p&gt;
&lt;p&gt;It doesn&amp;rsquo;t get us all of the way there to updating the references in our source code folder. That&amp;rsquo;s where projects, like Nu, are going to start showing up that leverage the idea of using the gems infrastructure to get the libraries from the ruby folders to your source code folder. You are going to see UppercuT come back soon with taking care of getting your gem built with the proper version.&lt;/p&gt;
&lt;p&gt;This is the start of something very cool.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;Related Posts&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;Before you comment about &amp;ldquo;cluttering&amp;rdquo; the ruby community, please be sure to read this (we&amp;rsquo;re with you on this):&amp;nbsp; &lt;a target="_blank" href="http://devlicio.us/blogs/rob_reynolds/archive/2010/07/19/gems-for-net-community-response.aspx" title="http://devlicio.us/blogs/rob_reynolds/archive/2010/07/19/gems-for-net-community-response.aspx"&gt;http://devlicio.us/blogs/rob_reynolds/archive/2010/07/19/gems-for-net-community-response.aspx&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a target="_blank" href="http://devlicio.us/blogs/rob_reynolds/archive/2010/07/16/how-to-gems-and-net.aspx"&gt;How To - Gems and .NET&lt;/a&gt;&amp;nbsp; and &lt;a target="_blank" href="http://devlicio.us/blogs/rob_reynolds/archive/2010/07/17/how-to-gems-and-net-dependencies-references.aspx"&gt;How To &amp;ndash; Gems &amp;amp; .NET - Dependencies (References)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a target="_blank" href="http://devlicio.us/blogs/rob_reynolds/archive/2010/07/20/how-to-uppercut-and-gems.aspx"&gt;Walkthrough &amp;ndash; Create Gems Even Easier With a Conventional Build (UppercuT)!&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a target="_blank" href="http://devlicio.us/blogs/rob_reynolds/archive/2010/07/26/the-future-of-net-open-source-software-delivery.aspx"&gt;The Future is Now!&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://devlicio.us/aggbug.aspx?PostID=61091" width="1" height="1"&gt;</description><category domain="http://devlicio.us/blogs/rob_reynolds/archive/tags/RoundhousE/default.aspx">RoundhousE</category><category domain="http://devlicio.us/blogs/rob_reynolds/archive/tags/SidePOP/default.aspx">SidePOP</category><category domain="http://devlicio.us/blogs/rob_reynolds/archive/tags/UppercuT/default.aspx">UppercuT</category><category domain="http://devlicio.us/blogs/rob_reynolds/archive/tags/Development/default.aspx">Development</category><category domain="http://devlicio.us/blogs/rob_reynolds/archive/tags/Tools/default.aspx">Tools</category><category domain="http://devlicio.us/blogs/rob_reynolds/archive/tags/.NET/default.aspx">.NET</category><category domain="http://devlicio.us/blogs/rob_reynolds/archive/tags/Gems/default.aspx">Gems</category></item><item><title>Chuck Norris Welcomes You</title><link>http://devlicio.us/blogs/rob_reynolds/archive/2010/04/17/chuck-norris-welcomes-you.aspx</link><pubDate>Sat, 17 Apr 2010 14:57:21 GMT</pubDate><guid isPermaLink="false">40756a8b-6212-4073-9d98-6c26781577de:57410</guid><dc:creator>Rob Reynolds</dc:creator><slash:comments>3</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://devlicio.us/blogs/rob_reynolds/rsscomments.aspx?PostID=57410</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://devlicio.us/blogs/rob_reynolds/commentapi.aspx?PostID=57410</wfw:comment><comments>http://devlicio.us/blogs/rob_reynolds/archive/2010/04/17/chuck-norris-welcomes-you.aspx#comments</comments><description>&lt;blockquote&gt;   &lt;p&gt;&amp;#160;&lt;a href="http://www.codesqueeze.com/the-ultimate-top-25-chuck-norris-the-programmer-jokes/" target="_blank"&gt;Chuck Norris doesn’t program with a keyboard. He stares the computer down until it does what he wants.&lt;/a&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;&lt;a href="http://devlicio.us/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rob_5F00_reynolds/image_5F00_62A08492.png"&gt;&lt;img style="border-right-width:0px;margin:10px 0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;" title="Chuck Norris welcomes you" border="0" alt="Chuck Norris welcomes you" align="right" src="http://devlicio.us/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rob_5F00_reynolds/image_5F00_thumb_5F00_42091F13.png" width="174" height="320" /&gt;&lt;/a&gt; All things need a name. We’ve tossed around a bunch of names for the framework of tools we’ve been working on, but one we kept coming back to was Chuck Norris. Why did we choose Chuck Norris? Well Chuck Norris sort of chose us. Everything we talked about, the name kept drawing us closer to it. We couldn’t escape Chuck Norris, no matter how hard we tried. So we gave in.&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;a href="http://www.chucknorrisfacts.com/node/101" target="_blank"&gt;Chuck Norris can divide by zero.&lt;/a&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;h4&gt;&lt;strong&gt;What is the &lt;/strong&gt;&lt;a href="http://groups.google.com/group/chucknorrisframework" target="_blank"&gt;&lt;strong&gt;Chuck Norris Framework&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;?&lt;u&gt; &lt;/u&gt;&lt;/strong&gt;&lt;/h4&gt;  &lt;p&gt;&lt;a href="http://twitter.com/drusellers" target="_blank"&gt;@drusellers&lt;/a&gt; and I have been working on a variety of tools:&lt;/p&gt;  &lt;p&gt;WarmuP - &lt;a href="http://github.com/chucknorris/warmup" target="_blank"&gt;http://github.com/chucknorris/warmup&lt;/a&gt; (Template your entire project/solution and create projects ready to code - From Zero to a Solution with everything in seconds. Your templates, your choices.)     &lt;br /&gt;UppercuT - &lt;a href="http://projectuppercut.org/"&gt;http://projectuppercut.org&lt;/a&gt; (Build with Conventions - Professional Builds in Moments, Not Days!) | Code also at &lt;a title="http://github.com/chucknorris/uppercut" href="http://github.com/chucknorris/uppercut" target="_blank"&gt;http://github.com/chucknorris/uppercut&lt;/a&gt;     &lt;br /&gt;DropkicK - &lt;a href="http://github.com/chucknorris/dropkick" target="_blank"&gt;http://github.com/chucknorris/dropkick&lt;/a&gt; (Deploy Fluently)     &lt;br /&gt;RoundhousE - &lt;a href="http://projectroundhouse.org/"&gt;http://projectroundhouse.org&lt;/a&gt; (Professional Database Management with Versioning) | Code also at &lt;a title="http://github.com/chucknorris/roundhouse" href="http://github.com/chucknorris/roundhouse" target="_blank"&gt;http://github.com/chucknorris/roundhouse&lt;/a&gt;     &lt;br /&gt;SidePOP - &lt;a href="http://sidepop.googlecode.com/"&gt;http://sidepop.googlecode.com&lt;/a&gt; (Does your application need to check email?)     &lt;br /&gt;HeadlocK - &lt;a href="http://github.com/chucknorris/headlock" target="_blank"&gt;http://github.com/chucknorris/headlock&lt;/a&gt; (Hash a directory so you can later know if anything has changed) &lt;/p&gt;  &lt;p&gt;Others – still in concept or vaporware &lt;/p&gt;  &lt;h4&gt;&lt;strong&gt;What’s in a Name?&lt;/strong&gt;&lt;/h4&gt;  &lt;p&gt;People ask why we choose such violent names for each tool of our framework? At first it was about whipping your code into shape, but after awhile the naming became, “How can we relate this to Chuck Norris?” People also ask why we uppercase the last letter of each name. Well, that’s more about making you ask questions…but there are a few reasons for it. &lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;a href="http://www.codesqueeze.com/the-ultimate-top-25-chuck-norris-the-programmer-jokes" target="_blank"&gt;Project managers never ask Chuck Norris for estimations…ever.&lt;/a&gt; &lt;/p&gt;    &lt;p&gt;&lt;a href="http://www.codesqueeze.com/the-ultimate-top-25-chuck-norris-the-programmer-jokes/" target="_blank"&gt;The class object inherits from Chuck Norris&lt;/a&gt;&lt;/p&gt;    &lt;p&gt;&lt;a href="http://www.codesqueeze.com/the-ultimate-top-25-chuck-norris-the-programmer-jokes/" target="_blank"&gt;Chuck Norris doesn’t need garbage collection because he doesn’t call .Dispose(), he calls .DropKick()&lt;/a&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;h4&gt;&lt;strong&gt;Call To Action&lt;/strong&gt;&lt;/h4&gt;  &lt;p&gt;So what are you waiting for? Join the &lt;a href="http://groups.google.com/group/chucknorrisframework" target="_blank"&gt;Google group&lt;/a&gt; today, download and play with the tools. &lt;/p&gt;  &lt;p&gt;And lastly, welcome to Chuck Norris. Or should I say Chuck Norris welcomes you…&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://devlicio.us/aggbug.aspx?PostID=57410" width="1" height="1"&gt;</description><category domain="http://devlicio.us/blogs/rob_reynolds/archive/tags/RoundhousE/default.aspx">RoundhousE</category><category domain="http://devlicio.us/blogs/rob_reynolds/archive/tags/SidePOP/default.aspx">SidePOP</category><category domain="http://devlicio.us/blogs/rob_reynolds/archive/tags/UppercuT/default.aspx">UppercuT</category><category domain="http://devlicio.us/blogs/rob_reynolds/archive/tags/Development/default.aspx">Development</category><category domain="http://devlicio.us/blogs/rob_reynolds/archive/tags/Tools/default.aspx">Tools</category><category domain="http://devlicio.us/blogs/rob_reynolds/archive/tags/.NET/default.aspx">.NET</category></item><item><title>Lessons In Building An Email Parser</title><link>http://devlicio.us/blogs/rob_reynolds/archive/2009/12/18/lessons-in-building-an-email-parser.aspx</link><pubDate>Fri, 18 Dec 2009 09:11:00 GMT</pubDate><guid isPermaLink="false">40756a8b-6212-4073-9d98-6c26781577de:54627</guid><dc:creator>Rob Reynolds</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://devlicio.us/blogs/rob_reynolds/rsscomments.aspx?PostID=54627</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://devlicio.us/blogs/rob_reynolds/commentapi.aspx?PostID=54627</wfw:comment><comments>http://devlicio.us/blogs/rob_reynolds/archive/2009/12/18/lessons-in-building-an-email-parser.aspx#comments</comments><description>&lt;h4&gt;&lt;span style="text-decoration:underline;"&gt;&lt;strong&gt;The Classic Infinite Email Loop&lt;/strong&gt;&lt;/span&gt; &lt;/h4&gt;
&lt;p&gt;When building an email parser, one must think about validating an email address that sends you a message. Why? Just because an email message has a from address does not already mean that it is a valid email address. When you&amp;#39;re building an auto-responder, not validating an email can cause an email loop. Some of you can already see where I&amp;rsquo;m going with this.&lt;/p&gt;
&lt;p&gt;I was building something in &lt;a target="_blank" href="http://bombali.googlecode.com"&gt;Bombali&lt;/a&gt; that would respond to emails when receiving them. When Bombali received a message from an address, Bombali would send a response. No checking on the address. In&amp;nbsp;the world of&amp;nbsp;computers, this is&amp;nbsp;a classic mistake.&amp;nbsp;In my head I hear the word &amp;quot;classic&amp;quot; as if it came from SNL and&amp;nbsp;the &amp;quot;Classic Peg&amp;quot; skits. Classssssss-ic (with laughing and shoulder shrugging) Mistake. Right? Well this is all new to me, I&amp;rsquo;ve never been able to do this programmatically until recently. So Bombali received a message with a no reply from address. It sent a response. Then it got a response from the postmaster saying that this was an invalid address. I bet you&amp;rsquo;re guessing what happens next? Yes, Bombali responded to the postmaster. And then the postmaster responded back. Over a matter of about 30 minutes there was quite a bit of traffic back and forth until I deleted the emails before Bombali could check them. At least I was smart enough to set the email checking to every half minute. &lt;/p&gt;
&lt;p&gt;How did I get past this? Validation. An authorized list form of validation. Interested? Read on dear reader. &lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;&lt;span style="text-decoration:underline;"&gt;SidePOP XmlConfigurator&lt;/span&gt;&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;I was exposing my configuration in the last &lt;a target="_blank" href="http://devlicio.us/blogs/rob_reynolds/archive/2009/12/08/how-to-check-email-programmatically-sidepop.aspx"&gt;post&lt;/a&gt;, so I built an &lt;a target="_blank" href="http://code.google.com/p/sidepop/source/browse/trunk/product/sidepop/runners/SidePopXmlConfigurator.cs"&gt;XmlConfigurator&lt;/a&gt; that does this for you and gives you back a list of Email Watchers (renamed SidePOPRunner).&lt;/p&gt;
&lt;pre name="code" class="c#"&gt;private void configure_mail_watcher()
{
    EmailWatcherConfigurator configurator = new SidePopXmlConfigurator();
    foreach (EmailWatcher emailWatcher in configurator.configure())
    {
        emailWatcher.MessagesReceived += runner_messages_received;
        emailWatcher.start();
    }
}&lt;/pre&gt;
&lt;h4&gt;&lt;strong&gt;&lt;span style="text-decoration:underline;"&gt;Subscriber for Receiving Email&lt;/span&gt;&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;The code above and the code below show how easy it is for your application to receive email. I map the email to a local object and then I pass that off to a function to parse and send a response.&lt;/p&gt;
&lt;pre name="code" class="c#"&gt;private void runner_messages_received(object sender, MessageListEventArgs e)
{
    IEnumerable&amp;lt;SidePOPMailMessage&amp;gt; messages = e.Messages;

    foreach (SidePOPMailMessage message in messages)
    {
        Email mail_message = Map.from(message).to&amp;lt;Email&amp;gt;();
        parse_and_send_response(mail_message);
    }
}&lt;/pre&gt;
&lt;p&gt;So now I am receiving email, but I need to parse it do determine what to do. So let&amp;rsquo;s show the parser first before the method for sending a response.&lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;&lt;span style="text-decoration:underline;"&gt;Really Simple Email Parser&lt;/span&gt;&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;This is a really simple parser. It&amp;rsquo;s not by any means what some people would use in production and that&amp;rsquo;s fine. It works for what Bombali needs. &lt;/p&gt;
&lt;pre name="code" class="c#"&gt;public MailQueryType parse(Email message, IList&amp;lt;IMonitor&amp;gt; monitors, IDictionary&amp;lt;string, ApprovalType&amp;gt; authorization_dictionary)
{
    MailQueryType query_type = MailQueryType.Authorizing;

    string user = message.from_address.to_lower();
    bool user_is_authorized = false;

    if (authorization_dictionary.ContainsKey(user))
    {
        ApprovalType user_is_approved = authorization_dictionary[user];
        if (user_is_approved == ApprovalType.Approved)
        {
            user_is_authorized = true;
        }
    }

    if (user_is_authorized)
    {
        query_type = MailQueryType.Help;
        string subject_and_body = message.subject + &amp;quot;|&amp;quot; + message.message_body;

        if (message_contains_status(subject_and_body)) query_type = MailQueryType.Status;
        if (message_contains_config(subject_and_body)) query_type = MailQueryType.Configuration;
        if (message_contains_down(subject_and_body)) query_type = MailQueryType.CurrentDownItems;
        if (message_contains_approve(subject_and_body)) query_type = MailQueryType.Authorized;
        if (message_contains_deny(subject_and_body)) query_type = MailQueryType.Denied;
        if (message_contains_version(subject_and_body)) query_type = MailQueryType.Version;
    }

    return query_type;
}&lt;/pre&gt;
&lt;p&gt;I have a MailQueryType so that I separate what how to respond from actually responding. What you can see is that I&amp;rsquo;m already checking to see if we have an approved user before I set a different MailQueryType. The mail parser just sends back how Bombali should respond to the message. &lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;&lt;span style="text-decoration:underline;"&gt;Sending a Response&lt;/span&gt;&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;In subscribing to receiving email, I passed the message to the method below. The second line of the method shows me passing the message off to the mail parser to find out how to respond.&amp;nbsp; The switch could probably be replaced by a Strategy pattern, but for now it works and it&amp;rsquo;s all I need.&lt;/p&gt;
&lt;pre name="code" class="c#"&gt;private void parse_and_send_response(Email mail_message)
{
    string respond_to = mail_message.from_address.to_lower();
    MailQueryType query_type = mail_processor.parse(mail_message, monitors, authorization_dictionary);
    Log.bound_to(this).Info(&amp;quot;{0} received a message from {1} of type {2}.&amp;quot;, ApplicationParameters.name, respond_to, query_type.ToString());

    string response_text = string.Empty;

    if (query_type == MailQueryType.Authorized || query_type == MailQueryType.Denied)
    {
        string[] body_words = mail_message.message_body.Split(&amp;#39; &amp;#39;);
        foreach (string body_word in body_words)
        {
            if (body_word.Contains(&amp;quot;@&amp;quot;))
            {
                respond_to = body_word.Replace(Environment.NewLine, &amp;quot;&amp;quot;);
                break;
            }
        }
    }

    switch (query_type)
    {
        case MailQueryType.Denied:
            authorization_dictionary.Add(respond_to, ApprovalType.Denied);
            return;
            break;
        case MailQueryType.Authorized:
            authorization_dictionary.Add(respond_to, ApprovalType.Approved);
            response_text = string.Format(&amp;quot;Congratulations - you have been approved!{0}Send &amp;#39;help&amp;#39; for options&amp;quot;, Environment.NewLine);
            break;
        case MailQueryType.Help:
            response_text =
                string.Format(
                    &amp;quot;Options - send one:{0} help - this menu{0} status - up time{0} config - all monitors{0} down - current monitors in error{0} version - current version&amp;quot;,
                    Environment.NewLine);
            break;
        case MailQueryType.Status:
            TimeSpan up_time_current = up_time.Elapsed;
            response_text = string.Format(&amp;quot;{0} has been up and running for {1} days {2} hours {3} minutes and {4} seconds.&amp;quot;, ApplicationParameters.name,
                                          up_time_current.Days, up_time_current.Hours, up_time_current.Minutes, up_time_current.Seconds);
            break;
        case MailQueryType.CurrentDownItems:
            response_text = string.Format(&amp;quot;Services currently down:{0}&amp;quot;, Environment.NewLine);
            foreach (IMonitor monitor in monitors)
            {
                if (monitor.who_to_notify_as_comma_separated_list.to_lower().Contains(respond_to))
                {
                    if (!monitor.status_is_good) response_text += string.Format(&amp;quot;{0}{1}&amp;quot;, monitor.name, Environment.NewLine);
                }
            }
            break;
        case MailQueryType.Authorizing:
            response_text =
                string.Format(&amp;quot;Bombali notified admin to add you to approved list. If you are added, you will receive a response.&amp;quot;);
            break;
        case MailQueryType.Version:
            response_text = string.Format(&amp;quot;Bombali is currently running version {0}.&amp;quot;, Version.get_version());
            break;
        default:
            response_text = string.Format(&amp;quot;{0} has not been implemented yet. Please watch for updates.&amp;quot;, query_type);
            break;
    }

    SendNotification
        .from(BombaliConfiguration.settings.email_from)
        .to(respond_to)
        .with_subject(&amp;quot;Bombali Response&amp;quot;)
        .with_message(response_text)
        .and_use_notification_host(BombaliConfiguration.settings.smtp_host);

    if (query_type == MailQueryType.Authorizing)
    {
        SendNotification
        .from(BombaliConfiguration.settings.email_from)
        .to(BombaliConfiguration.settings.administrator_email)
        .with_subject(&amp;quot;Bombali Request&amp;quot;)
        .with_message(string.Format(&amp;quot;{0} reqests approval. Send approve/deny w/email address. Ex. &amp;#39;deny bob@nowhere.com&amp;#39;&amp;quot;, respond_to))
        .and_use_notification_host(BombaliConfiguration.settings.smtp_host);
    }

}&lt;/pre&gt;
&lt;p&gt;You&amp;rsquo;ll notice that I&amp;rsquo;m authorizing any new email addresses that send an email to Bombali before allowing them access to the application. I do that by having an administrator contact I can send a request for approve or deny to before allowing access. I also send an email back to the sender letting them know they are in the process of being approved. At most I would send one email to a bad address. As administrator, the email can be validated by a human. And I only respond to an authorized list. I could also build in something to validate the email by checking for a response from a post master telling me the address doesn&amp;rsquo;t exist.&lt;/p&gt;
&lt;p&gt;So remember readers - always check your sources. Otherwise you might get in an infinite loop. And that would be bad.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://devlicio.us/aggbug.aspx?PostID=54627" width="1" height="1"&gt;</description><category domain="http://devlicio.us/blogs/rob_reynolds/archive/tags/HowTo/default.aspx">HowTo</category><category domain="http://devlicio.us/blogs/rob_reynolds/archive/tags/SidePOP/default.aspx">SidePOP</category><category domain="http://devlicio.us/blogs/rob_reynolds/archive/tags/Tools/default.aspx">Tools</category></item><item><title>How To Check Email Programmatically - SidePOP</title><link>http://devlicio.us/blogs/rob_reynolds/archive/2009/12/08/how-to-check-email-programmatically-sidepop.aspx</link><pubDate>Tue, 08 Dec 2009 06:46:00 GMT</pubDate><guid isPermaLink="false">40756a8b-6212-4073-9d98-6c26781577de:54347</guid><dc:creator>Rob Reynolds</dc:creator><slash:comments>2</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://devlicio.us/blogs/rob_reynolds/rsscomments.aspx?PostID=54347</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://devlicio.us/blogs/rob_reynolds/commentapi.aspx?PostID=54347</wfw:comment><comments>http://devlicio.us/blogs/rob_reynolds/archive/2009/12/08/how-to-check-email-programmatically-sidepop.aspx#comments</comments><description>&lt;h4&gt;&lt;strong&gt;&lt;span style="text-decoration:underline;"&gt;Background&lt;/span&gt;&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;Sending email has long been easy to do with the .NET Framework. There really hasn&amp;rsquo;t been a facility for checking email though. I recently had a need to be able to check email with and send a response with &lt;a target="_blank" href="http://bombali.googlecode.com/"&gt;Bombali&lt;/a&gt; (a monitoring tool). I went searching for examples or a solution I could use. I found a few articles on this from a few years ago including the &lt;a target="_blank" href="http://www.codeproject.com/KB/IP/NetPopMimeClient.aspx"&gt;.NET POP3 MIME Client&lt;/a&gt;.&amp;nbsp; I never found anything that was free and I never found anything that was easy to configure. Those who know me know I have a tinge of the NIH (not invented here), especially when there are no free alternatives. So I created my own based on the articles I had read. And in the spirit of chucknorris, I named it &lt;a target="_blank" href="http://sidepop.googlecode.com/"&gt;SidePOP&lt;/a&gt;! &lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;&lt;span style="text-decoration:underline;"&gt;Configuration&lt;/span&gt;&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;Configuration for receiving email should be easy. Feast your eyes on all that is required for configuration (and for those of you who dislike XML, it&amp;rsquo;s not required &amp;ndash; you can configure all in code):&lt;/p&gt;
&lt;pre name="code" class="xml"&gt;&amp;lt;configSections&amp;gt;
  &amp;lt;section name=&amp;quot;sidepop&amp;quot; type=&amp;quot;sidepop.configuration.SidePOPConfiguration, sidepop&amp;quot;/&amp;gt;
&amp;lt;/configSections&amp;gt;

&amp;lt;!-- 110 is normal POP3 SSL uses port 995--&amp;gt;
&amp;lt;sidepop&amp;gt;
  &amp;lt;accounts&amp;gt;
    &amp;lt;add hostName=&amp;quot;mail.somewhere&amp;quot; userName=&amp;quot;yep&amp;quot; password=&amp;quot;&amp;quot; minutesBetweenChecks=&amp;quot;.1&amp;quot; /&amp;gt;
    &amp;lt;add name=&amp;quot;Number1&amp;quot; description=&amp;quot;Main account&amp;quot; enabled=&amp;quot;true&amp;quot; hostName=&amp;quot;mail.somewhere.net&amp;quot; hostPort=&amp;quot;110&amp;quot; useSSL=&amp;quot;false&amp;quot; userName=&amp;quot;&amp;quot; password=&amp;quot;&amp;quot; minutesBetweenChecks=&amp;quot;1&amp;quot; timeoutInMinutes=&amp;quot;1&amp;quot;  /&amp;gt;
  &amp;lt;/accounts&amp;gt;
&amp;lt;/sidepop&amp;gt;&lt;/pre&gt;
&lt;p&gt;You see there are two items here. The first one has the required items in it. The second one is the entire set of items to configure.&amp;nbsp; Notice that we are asking for a password in plaintext. This is where you might think about encrypting this section somehow.&lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;&lt;span style="text-decoration:underline;"&gt;Code Setup&lt;/span&gt;&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;Configuring SidePOP to run is a little more verbose that I might like right now. Looking below you see that it&amp;rsquo;s still not that much code. I hope to set up a facility to automatically look at the configuration file and configure SidePOP (for those that like XML). If someone wants to send me a patch as well, that would be awesome.&lt;/p&gt;
&lt;pre name="code" class="c#"&gt;private void configure_mail_watcher()
{
    foreach (AccountConfigurationElement account in SidePOPConfiguration.settings.accounts)
    {
        if (account.enabled)
        {
            SidePopRunner runner = new SidePopRunner(new DefaultPop3Client(account.hostName, account.hostPort,
                                     account.useSSL, account.userName,
                                     account.password), account.minutes_between_checks);
            runner.MessagesReceived += runner_messages_received;
            runner.run();
            Log.bound_to(this).Info(&amp;quot;{0} is configured to watch for messages with user {1} at {2} every {3} minutes.&amp;quot;, ApplicationParameters.name,
                                    account.userName, account.hostName, account.minutes_between_checks);
        }
    }
}

private void runner_messages_received(object sender, MessageListEventArgs e)
{
    IEnumerable&amp;lt;SidePOPMailMessage&amp;gt; messages = e.Messages;

    const string subject = &amp;quot;Bombali Response&amp;quot;;
    TimeSpan up_time_current = up_time.Elapsed;
    string text_message = string.Format(&amp;quot;{0} has been up and running for {1} days {2} hours {3} minutes and {4} seconds.&amp;quot;, ApplicationParameters.name, up_time_current.Days, up_time_current.Hours, up_time_current.Minutes, up_time_current.Seconds);

    foreach (SidePOPMailMessage message in messages)
    {
        Log.bound_to(this).Info(&amp;quot;{0} received a message from {1}. Responding that service is still running.&amp;quot;,ApplicationParameters.name,message.From.Address);
    
        SendNotification.from(BombaliConfiguration.settings.email_from).to(message.From.Address).with_subject(
        subject).with_message(text_message).and_use_notification_host(BombaliConfiguration.settings.smtp_host);
    }
}&lt;/pre&gt;
&lt;p&gt;When I start the service, I call the method configure_mail_watcher(). Because I can have multiple accounts I can check with SidePOP, I am going to loop through the settings and check each one to ensure they are enabled. If so, then I am going to set up a SidePopRunner and subscribe to runner_messages_received (this may not work with multiple accounts, I haven&amp;rsquo;t yet tested that).&amp;nbsp; Then I kick off the runner for that account.&lt;/p&gt;
&lt;p&gt;I could instead subscribe to runner.MessageReceived (instead of runner.Message&lt;strong&gt;s&lt;/strong&gt;Received) for getting an event notification for every message instead of batching it up to a list if I desired.&lt;/p&gt;
&lt;p&gt;When a message is received, I find out how long the service has been up. I didn&amp;rsquo;t show it here, but &lt;em&gt;up_time&lt;/em&gt; is a System.Diagnostics.Stopwatch. In the constructor I start it. Now I just capture how long it has been up. Then for each message, I send a response to the sender of the email address telling them how long the service has been up. To add more sophistication, I could very easily add a rules engine here to process the message based on a list of rules looking for keywords in the email.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s all I need to do. Now I&amp;rsquo;m up and ready to rock.&lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;&lt;span style="text-decoration:underline;"&gt;What It Looks Like&lt;/span&gt;&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;Here is what it looks like running with Bombali. I send the service a text message. This is what it logs.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;2009-12-07 23:59:05,875 5 [INFO ] - Bombali received a message from &lt;em&gt;someone @ somewhere.net&lt;/em&gt;. Responding that service is still running. &lt;br /&gt;2009-12-07 23:59:05,875 5 [INFO ] - Sending email to &lt;em&gt;someone @ somewhere.net&lt;/em&gt; with subject &amp;quot;Bombali Response&amp;quot; and message: &lt;br /&gt;Bombali has been up and running for 0 days 0 hours 31 minutes and 22 seconds.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is what I get from my phone. &lt;/p&gt;
&lt;p&gt;&lt;a href="http://devlicio.us/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rob_5F00_reynolds/image_5F00_7E751386.png"&gt;&lt;img border="0" width="364" src="http://devlicio.us/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rob_5F00_reynolds/image_5F00_thumb_5F00_769CFB17.png" alt="Bombali has been up and running for 0 days 0 hours 31 minutes and 22 seconds." height="484" style="border-right-width:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;" title="Bombali has been up and running for 0 days 0 hours 31 minutes and 22 seconds." /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;Now I know that my service is still up and running with a simple text. All for the low price of a few lines of code and the sidePOP.dll library.&lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;&lt;span style="text-decoration:underline;"&gt;Conclusion&lt;/span&gt;&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;&lt;a target="_blank" href="http://sidepop.googlecode.com/"&gt;SidePOP&lt;/a&gt; gives me a level of sophistication that I didn&amp;rsquo;t have before. Now that I have access to get email, I could very easily add rules to do different things based on the content of the email received. How often have you wanted your application to check email and just didn&amp;rsquo;t want to pay the price for the products out there that can do this? Now it&amp;rsquo;s completely free with SidePOP.&lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;&lt;span style="text-decoration:underline;"&gt;Download SidePOP&lt;/span&gt;&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;NOTE: This is still early. Any part of the configuration could change. Be sure you take a look at the sample app to always have the newest configuration. Register any bugs you find here: &lt;a target="_blank" href="http://code.google.com/p/sidepop/issues/list" title="http://code.google.com/p/sidepop/issues/list"&gt;http://code.google.com/p/sidepop/issues/list&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;WARNING: SidePOP will delete your email when it checks it. That&amp;rsquo;s how it can be sure it&amp;rsquo;s only dealing with new messages every time. Do not test on an account you care about. You&amp;rsquo;ve been warned.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;SVN here: &lt;a target="_blank" href="http://sidepop.googlecode.com/svn/trunk/" title="http://sidepop.googlecode.com/svn/trunk/"&gt;http://sidepop.googlecode.com/svn/trunk/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Downloads here: &lt;a target="_blank" href="http://code.google.com/p/sidepop/downloads/list" title="http://code.google.com/p/sidepop/downloads/list"&gt;http://code.google.com/p/sidepop/downloads/list&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://devlicio.us/aggbug.aspx?PostID=54347" width="1" height="1"&gt;</description><category domain="http://devlicio.us/blogs/rob_reynolds/archive/tags/HowTo/default.aspx">HowTo</category><category domain="http://devlicio.us/blogs/rob_reynolds/archive/tags/SidePOP/default.aspx">SidePOP</category><category domain="http://devlicio.us/blogs/rob_reynolds/archive/tags/Tools/default.aspx">Tools</category></item></channel></rss>