Friday, December 17, 2010

Ruby to MBox format.

I have over the past 20+ years written many scripts to deal with incoming mail.
I can process statistics from machine generated alert E-mails, rebroadcast E-mails and generate pages from them based on there content.

I was using a the IMAPClient library in Perl for this, but when my IMAP Mail server was migrate to an SSL based TLS/IMAP everything broke.

TLS encrypted port 993 RFC2595 RFC3501

After many long hours of struggling to get IMAPClient to work over SSL I just had to give up. It looks like something is just broken in that lib, I tried opening my own SSL socket then passing it to the lib, I tried having the lib itself connect to the SSL socket, no luck.

The Ruby net/imap just seems better written and it does work. Unfortunately it's lacking the message_to_file  function which I had to replace that functionality.

A small change in the scripts below could also simulate .forward also or support mail dir.
If you do that, please send me a copy  

In Perl for Non-secure IMAP

use Mail::IMAPClient;
my $imap = Mail::IMAPClient->new( Server       => 'mail.yourdomain:143',
                                   User         => 'jsokol',
                                   Password     => 'yea-right')
        or die "IMAP Failure: $@";

 foreach my $box qw( alarmpoint ) {
   my $file = "/uhome/jsokol/crapmail/". $box;

   my @msgs = $imap->search('ALL')
        or die "Couldn't get all messages\n";

   foreach my $msg (@msgs) {
     open my $pipe, "| formail >> $file"
       or die("Formail Open Pipe Error: $!");
     $imap->message_to_file($pipe, $msg);
     close $pipe
       or die("Formail Close Pipe Error: $!");

   # Now expunge the messages and close the folder


I am just learning Ruby, so please excuse some of this code.

In Ruby secure TLS/IMAP
require 'net/imap'

        server = ""
        port = 993
        ssl = true
        username = "jsokol"
        password = "yea-right"

        Net::IMAP.debug = false
        conn =, port, ssl)
        resp = conn.login(username, password)'test')['ALL']).each do |sequence|

                env = conn.fetch( sequence,"ENVELOPE")[0].attr['ENVELOPE']
                xdate =" ");

               wkday = xdate[0].sub(/,/,"")
               day = xdate[1]
               month = xdate[2]
               year = xdate[3]
               time = xdate[4]

               if (day.length < 2)
                   day = "0" + day

                box  = env.from[0].mailbox  + "@" +  env.from[0].host + "  " + wkday + " " + month + " " + day + " " + time + " " + year

                fetch_result = conn.fetch( sequence,  "RFC822")[0].attr['RFC822']
                if fetch_result
            "MAILOUT" , "a") {|file|  file.write ("From #{box}\n#{fetch_result}\n\n\n") }

       , "+FLAGS", [:Deleted]) # remove this line if you don't want to deltete these E-mails.
        conn.expunge # remove this line if you don't want to deltete these E-mails.

No comments: