Sync your Email with Perl and JPilot

30 November -0001

So I'm using a PDA again, after giving up on them for a long time. Currently I'm using a Palm Zire m150, mainly because its got a rechargable battery. After trying all the different PIM programs out there for connecting I settled on JPilot, which is a really cool little program. My first challenge in using the Zire was getting a mail program on it (it doesn't come with an email reading program). To do this I used the freeware program Filez. I downloaded it to my Zire, beamed it to a Handspring I had (you could use any Palm with Mail on it though, or borrow a friend's), then opened it up on the Handspring and beamed the Handspring's Mail program back to the Zire. Note that when you do this you've got to check the 'ROM' box in Filez and beam both MailDB and Mail. Once you do this you can use the JPilot Mail plugin to HotSync your mail with the Zire. Problem is, the Mail plugin is a stickler and you have to set up the 'Folder' option in preferences to point to a single, specially formatted file for it to import your mail (you can't point it at Evolution's Inbox folder and expect it to find all your mail). So, I puzzled this over, and eventually wrote a Perl script to contact my POP3 server directly and pull the latest 15 mails, format them and drop them into a single file that I'm pointing JPilot to:

Screenshot of JPilot

This file happens to be /home/jkeane/Mail/myMail, but you could use whatever you want. The Perl script I use is as follows:

#!/usr/bin/perl -w

# Load Modules
use Mail::POP3Client;

#beging POP3 display
my $pop = new Mail::POP3Client(
	    HOST => 'yourServer',
	    USER => 'yourUserName',
	    PASSWORD => 'yourPassword',
	    );
    #$pop->Connect();
	$popTotal = $pop->Count();
	#print $popTotal;

#run back through the POP3 list
$min = $popTotal - 15;
for( $i=$popTotal; $i >= $min; $i-- ) {
  $myHeader = $pop->Head($i);

  #replace all < and > with HTML ASCII code
  #$myHeader =~ s/</<\;/g;
  #$myHeader =~ s/>/>\;/g;

  #escape all single quotes
  $myHeader =~ s/'/'\;/g;

  #replace all line breaks with <BR> tags
  $myHeader =~ s/\n/<br>/g;

  ########################################################
  ####		BREAK UP MESSAGE FOR INSERT         ####
  ########################################################

  #date ex(Date: Thu, 12 Jun 2003 13:01:56 -0500)
  $myHeader =~ s/Date:/Date:/gi;
  $dateStart = index($myHeader, "<br>Date:") + 10;
  $dateEnd = index($myHeader, "<br>", $dateStart+9);
  $dateLen = $dateEnd - $dateStart;
  $dateString = substr($myHeader, $dateStart, $dateLen);

  #sender
  $myHeader =~ s/From:/From:/gi;
  $fromStart = index($myHeader, "From:");
  if ($fromStart > -1) {
    $fromStart = $fromStart + 5;
    $fromEnd = index($myHeader, "<br>", $fromStart) - 1;
    $theFrom = substr($myHeader, $fromStart, ($fromEnd-$fromStart));
  }
  else {
    $theFrom = '';
  }
  #subject
  $myHeader =~ s/Subject:/Subject:/gi;
  $subjStart = index($myHeader, "Subject:");
  if ($subjStart > -1) {
    $subjStart = $subjStart + 8;
    $subjEnd = index($myHeader, "<br>", $subjStart);
    $theSubject = substr($myHeader, $subjStart, ($subjEnd-$subjStart));
  }
  else {
    $theSubject = '';
  }
  #boundary(if exists) - translate header so it matches case
  $myHeader =~ s/boundary=/boundary=/gi;
  $boundStart = index($myHeader, "boundary=");
  if ($boundStart > -1) {
    #note we have to adjust for quotes around the boundary
    $boundStart = $boundStart + 10;
    $boundEnd = index($myHeader, "<br>", $boundStart);
    $theBoundary = substr($myHeader,$boundStart,($boundEnd-$boundStart-2));
  }
  else {
    $theBoundary = '';
  }

  #grab the message body
  $myBody = $pop->Body($i);

  #grab any extras
  if (length($theBoundary) == 0) {
    $theAttach = '';
  }
  else {
    #if there is a boundary then we have to parse out the first 
    #part of the body then the attachments
    $boundaryLen = length($theBoundary);
    #find the two line breaks after the first MIME header
    $catcher = "7bit";
    $firstDelim = index($myBody, $theBoundary);
    $firstDelim = $firstDelim + $boundaryLen + 1;
    $myBodyStart = index($myBody, $catcher, $firstDelim);
    $myBodyStart = $myBodyStart + 4;
    #chop out the point from the two lines to the second boundary
    $myBodyEnd = index($myBody, $theBoundary, $myBodyStart);
    $theBodyLen = $myBodyEnd - $myBodyStart;
    $myBodyMessage = substr($myBody, $myBodyStart, $theBodyLen);

    $catchAttach = index($myBody, $theBoundary, ($myBodyStart + $theBodyLen));
    $theAttach = substr($myBody,$catchAttach,(length($myBody)-$catchAttach));
    #print "$catchAttach<BR>";
    # $myBody = substr($myBody, 0, $catchAttach);
    $myBody = $myBodyMessage;
  }

  #escape single quotes from the attachment
  $theAttach =~ s/'/\\'/g;

  #escape single quotes from the message body
  #$myBody =~ s/'/'\;/g;

  # fire at will
  print "From  " . $theFrom . " " . $dateString . "\n";
  print "From: " . $theFrom . "\n";
  print "Date: " . $dateString . "\n";
  print "Subject: " . $theSubject . "\n";
  print "Status: RO\r\n\r\n";
  print $myBody . "\r\n\r\n";

}

# clean up
$pop->Close();

Note that you've got to get the Mail::POP3Client module from CPAN or somewhere. Now, this program will just spill out the mail, it won't put it into a text file or anything, so I'm using the following shell script to actually fire it off:

#!/bin/bash


perl /home/jkeane/Mail/getMail.pl > /home/jkeane/Mail/myMail

And then you modify your /etc/crontab and add:

0,15,30,45 * * * * username /path/to/your/script.sh

And you're all set. This schedules the program to run every 15 minutes and kick back the file myMail. You can click the 'Get' button in JPilot to test out your configuration and after that JPilot should import the mail automatically when you HotSync.