Dashboard

Feb 07 18:44 | RT @googlenexus: Introducing Chrome for Android Beta, available for Android 4.0 #ICS devices in select countries and languages: http://t ...
Feb 06 18:08 | My really simple example on how to add CDN path to the @H5BP build script. http://t.co/3SJQhhWS
Feb 06 17:05 | RT @h5bp: HTML5 Boilerplate hits 3.0! Lighter and more robust: http://t.co/8kM7Ikp2

idlemailcheck v0.0.1 released – IMAP IDLE mail check with Snarl notification for Perl

August 28th 2009

Initially logged into Gmail

Since there has been some interest in using IMAP IDLE, Perl and Snarl, I wrote a cleaner more useful proof of concept that I have named idlemailcheck. Since I’ve never used Google Code, I decided to try it out and host the code there: idlemailcheck @ Google Code.

Email received and displayed as Snarl notification

The code is very raw and could use a improvement. It is very much a proof of concept and run it at your own risk. To see what it looks like in action, I’ve included a few screenshots of the Snarl notifications that appear over there on the left. The very nice icon comes from a Jonas Rask Design, and is free for personal use. This version does not play a sound, but subsequent versions will make that an option. I cannot stress enough that this is a proof of concept and that expectations should be low in this every version.

With that said, the script actually works fine in my limited testing. I don’t have a long term test record of it, but that will come with time. Before running the script you’ll need a few things installed.

  1. Snarl for Windows
  2. Win32::Snarl
  3. IO::Socket::SSL
  4. Mail::IMAPClient

You’ll also need to set the IMAP server address (the IMAP server must support IDLE) as well as your username and password. The path to the icon also needs to be set in the script. It does output debug information on the command line, so if something goes wrong, check your terminal window. I’ve had success running the script in Cygwin, but running the script within ActiveState’s ActivePerl should also be fine.

With that, I give you idlemailcheck v0.0.1, released under the GPL v2. You can view the code below, but if you’re looking to play with it, be sure to download the code and icon from the download page.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
#!/usr/bin/env perl
#######################################
#
#  idlemailcheck - IMAP IDLE mail check with Snarl notification
# 
#  Copyright (C) Justin Ribeiro <justin@justinribeiro.com>
#  Project Page - http://www.justinribeiro.com/  
# 	  
#   This program is free software; you can redistribute it and/or
#   modify it under the terms of the GNU General Public License
#   as published by the Free Software Foundation; either version 2 of
#   the License or (at your option) any later version.
#   
#   This program is distributed in the hope that it will be
#   useful, but WITHOUT ANY WARRANTY; without even the implied warranty
#   of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU General Public License for more details.
#   
#   You should have received a copy of the GNU General Public License
#   along with this program; if not, write to the Free Software
#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
#   USA
#
#   08/28/2009
#	JDR - Initial Concept Release 0.0.1
#
#  The script logs into an IMAP server of your  choice (which must support 
#  the IDLE command), sits at IDLE until the mail server has a new email, and 
#  then returns a Snarl notification when new mail arrives.
#
#  This connect portion of the script is based on the Gmail connect script at Perl Monks 
#  that was written by polettix and refined by markov: http://www.perlmonks.org/?node_id=649742
#
#  Requirements
#  1. Snarl for Windows (http://www.fullphat.net/)
#  2. Win32::Snarl
#  3. IO::Socket::SSL
#  4. Mail::IMAPClient
#
#  You must set the variables below for your specific IMAP server. If you want the icon
#  to appear, make sure you update to the full path as in the example below.
#
#  Tested with:
#
#  * Gmail 
#  * Google Apps for Domain
#
#  Feel free to make changes and additions;  I'm open to suggestions, fixes, and just
#  plain better ways to do things.
#  
#  Released under the GPL License.  Use at your own risk. 
#
#######################################
 
use warnings;
use strict;
use Mail::IMAPClient;
use IO::Socket::SSL;
use Win32::Snarl;
 
#### SETUP - YOU MUST SET THE FOLLOWING OR NOTHING WILL WORK
my $IMAP_server = "imap.gmail.com";
my $IMAP_port = "993";
my $IMAP_user = "";
my $IMAP_password = "";
my $SNARL_disptime = 7; # number of seconds to display snarls alerts
 
# path to icon
# icon from Jonas Rask Design http://jonasraskdesign.com/ (free for personal use)
# if you use a differnt icon, it must be 128x128 png
my $use_icon = "C:\\path\\to\\stamp.png";
 
 
#### EDITING BELOW AT OWN RISK
 
# Connect to the IMAP server via SSL
my $socket = IO::Socket::SSL->new(
   PeerAddr => $IMAP_server,
   PeerPort => $IMAP_port,
  )
  or die "socket(): $@";
 
# Build up a client attached to the SSL socket.
# Login is automatic as usual when we provide User and Password
my $client = Mail::IMAPClient->new(
   Socket   => $socket,
   User     => $IMAP_user,
   Password => $IMAP_password,
  )
  or die "new(): $@";
 
# we set Uid to false so that we can use the message sequence number to email information
$client->Uid(0);
 
# need these for later
my $noidle = 0;
my $last = 0;
my $buf;
my $bytes_read;
my $my_ID;
my $msg_count;
 
# Do something just to see that it's all ok
if ($client->IsAuthenticated()) 
{
   my $winAuth = Win32::Snarl::ShowMessage('Gmail Authenticated', 'You are now logged into Gmail.', $SNARL_disptime, $use_icon);
   print "Log in successful.\n";
 
   # open inbox folder
   $client->select("INBOX");
 
	# idle the connection	
	my $idle = $client->idle or warn "Couldn't idle: $@\n";
	print "IMAP now idle....waiting for email\n";
 
	# we sit an wait for the service to return some data
	while($bytes_read = $socket->sysread($buf, 4096)) 
	{
		# looks like we have something
		print "Read $bytes_read bytes from the socket...\n";
 
		# what's in the buffer
		print "Data: \n" . $buf . "\n";
 
		# grab one line at a time from the buffer
		while ( $buf =~ s/^(.*?\R)//o )
        {
        	# get the current buffer line
            my $current_line = $1;
 
    		# looking for a valid respone
            if ( $current_line !~ s/\s*\{(\d+)\}\R$//o ) 
            {	
            	# we only want "* XXX EXISTS" commands from the IMAP server, where XXX is the message sequence number
      			# $last != 1 is to make sure this isn't the last EXISTS command after an EXPUNGE; not a new message senario
            	if ( $current_line =~ s/EXISTS//g && $last != 1)
            	{
 
            		# we have to end the IDLE before we can get message information, otherwise the IMAP server will get angry
	            	$client->done($idle) or warn "Error from done: $@\n";
 
            		#check the unseen_count; this is a precaution, because for some reason Gmail at times responds with a new message notifcation, but's it's really not.
            		$msg_count = $client->unseen_count||0;       	
 
            		if ($msg_count > 0)
            		{
 
	            		# grab the message sequence number from the string
	            		$current_line =~ s/\D//g;
	            		$my_ID = $current_line;
	            		print "MID = " . $my_ID . "\n";
 
						# Email Data: Sender's address 
	  					my $from = $client->get_header($my_ID, "From");
	  					$from =~ s/<[^>]*>//g; #strip the email, only display the sender's name
 
	  					# Email Data: Subject
						my $subject = $client->get_header($my_ID, "Subject");
 
	  					# Send event to Snarl
	  					my $winNM = Win32::Snarl::ShowMessage($from, $subject, $SNARL_disptime, $use_icon);
 
						# make sure we keep the seen flag unset so the message stays unread
	      				$client->unset_flag("Seen",$my_ID) or die "$0: Could not unset_flag: $@\n"; #
 
	      				# restart the IDLE
	      				$idle = $client->idle or warn "Couldn't idle: $@\n";
						print "IMAP now idle....waiting for email\n";
 
      					next;
            		}
            		else
            		{
            			$idle = $client->idle or warn "Couldn't idle: $@\n";
						print "IMAP now idle....waiting for email\n";
            		}
            	}
            	else
            	{
            		# we had something other than EXISTS
            		$last = 1;
            	}
            }
        }
        $last = 0;
	}
 
	# kill the IDLE
	$client->done($idle) or warn "Error from done: $@\n";
 
	# Say bye
	$client->logout();
 }
 else
 {
 	# ahh !@#$.
 	print "Login failed.";
 }

Reader Responses

Skip to Response Form

1
Fredrik says:
November 12, 14:27

Hi,
I have tried your script and it works… for 30 minutes. My ISP’s IMAP serves does what most IMAP servers does: drop you if there is a 30 minutes inactivety. I have tried a couple of different approaches to get around this; *using threads -no luck. trid to use sleep(60*15) togehter with the part where the socket waits for data -no luck. In both cases, the code hangs and stops responding. have you got any ideas of how to solve this? I will continue on my side ’til I got a solution. Thanks for the code so far. It’s been fun poking around with it.

2
December 08, 10:02

@Fredrik, I do have a solution to this problem.

What I missed the first time in the RFC for use of the IDLE command: “clients using IDLE are advised to terminate the IDLE and re-issue it at least every 29 minutes to avoid being logged off.”

Basically the script needs to be aware of how long the IDLE session has been open, and at 29 minutes, disconnect and reconnect. I’m working on this now, and should have a fixed version at the end of the week.

Comment on this Entry

About This Entry

You are reading "idlemailcheck v0.0.1 released – IMAP IDLE mail check with Snarl notification for Perl", and entry posted on 28 August, 2009 and filed under development, perl, Snarl, software.

0 responses to this entry. 0 blog reactions. Add your response or trackback from your own site.