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

How to work with Mail::IMAPClient IDLE command and Perl socket

August 27th 2009

NOTE: The following example is deprecated with the May 2010 3.25 release of Mail::IMAPClient. See Phil’s IDLE example, which uses the new idle_data() and makes life easier.

I’ve been ill recently and I haven’t had time to refine this to what I want it to be, but I’m going to put it out there since I can’t find a single example of how to do this otherwise. How exactly do you use the IDLE command that the Mail::IMAPClient implements? The short answer is a Perl socket read. The longer answer is the following short piece of code.

I by no means am expert when it comes to Perl, and I’m even less of an expert when it comes to the use of sockets. The following small example does work, though I’m sure someone can offer a much more refined version. The following script is based on the Gmail connect script at Perl Monks that was written by polettix and refined by markov. They did a nice job and I simply added to their example.

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
#!/usr/bin/env perl
use warnings;
use Mail::IMAPClient;
use IO::Socket::SSL;
 
# Connect to the IMAP server via SSL
my $socket = IO::Socket::SSL->new(
   PeerAddr => 'imap.gmail.com',
   PeerPort => 993,
  )
  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     => 'yourusername',
   Password => 'yourpass',
  )
  or die "new(): $@";
 
# Do something just to see that it's all ok
if ($client->IsAuthenticated()) {
   print "Logged in.\n";
 
   # open inbox folder
   $client->select("INBOX");
 
	my $idle = $client->idle or warn "Couldn't idle: $@\n";
	print "IMAP now idle....waiting for email\n";
 
	while($bytes_read = $socket->sysread($buf, 4096)) 
	{
		print "Read $bytes_read bytes from the socket...\n";
		print "Data: \n" . $buf . "\n";
		print "IMAP now idle....waiting for email\n";
		$client->done($idle) or warn "Error from done: $@\n";
		$client->idle or warn "Couldn't idle: $@\n";
	}
 
	$client->done($idle) or warn "Error from done: $@\n";
 
	# Say bye
	$client->logout();
 }

A simple set of output from the test script

The example above requires you change out the username and password, and presumes that you’re connecting to Gmail (or in my case, Google Apps for Domain). Since Google now offers the IDLE command, the output looks something like the screenshot to the left. It’s very basic output (this was only a quick test), but the connection sits in idle and waits for the IMAP server to return data to the open socket. It’s very quick in my limited tests (there’s very little delay). I haven’t worked out all the kinks in this little test, but it gives you some idea on how to read the socket in conjunction with IDLE.

This all came about because I’ve been working with a combination of Snarl (a notification system for Windows) and it’s Perl module Win32::Snarl for alerts from various scripts. Both Snarl and the Perl module work quite well. Here’s the same script, but with Snarl support (it will display alerts through Snarl).

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
#!/usr/bin/env perl
use warnings;
use Mail::IMAPClient;
use IO::Socket::SSL;
use Win32::Snarl;
 
# Connect to the IMAP server via SSL
my $socket = IO::Socket::SSL->new(
   PeerAddr => 'imap.gmail.com',
   PeerPort => 993,
  )
  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     => 'yourusername',
   Password => 'yourpass',
  )
  or die "new(): $@";
 
# 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.', 5);
   print "Logged in.\n";
 
   # open inbox folder
   $client->select("INBOX");
 
	my $idle = $client->idle or warn "Couldn't idle: $@\n";
	print "IMAP now idle....waiting for email\n";
 
	while($bytes_read = $socket->sysread($buf, 4096)) 
	{
		print "Read $bytes_read bytes from the socket...\n";
		print "Data: \n" . $buf . "\n";
		print "IMAP now idle....waiting for email\n";
		my $winNM = Win32::Snarl::ShowMessage('New Email', $buf, 5);
		$client->done($idle) or warn "Error from done: $@\n";
		$client->idle or warn "Couldn't idle: $@\n";
	}
 
	$client->done($idle) or warn "Error from done: $@\n";
 
	# Say bye
	$client->logout();
 }

Your mileage may vary with the examples above; they’re brief to say the least. My goal is to write a very light Gmail check script, along with adding Snarl notifications to some of my other perl scripts. At least when I’m feeling better.

Reader Responses

Skip to Response Form

1
anonymous says:
June 01, 0:26

I’m afraid your method is quite unwise; you deliberately skip the responses that trigger your session. In your example session, the Mail::IMAPClient will have missed the existence of new messages notified by the “* XXX exists” messages. Refer to Mail::IMAPclient documentation about imap_data method and redesign using select()-style function instead of sysread.

2
June 01, 9:02

@anonymous I appreciate you bringing to my attention the update to Mail::IMAPclient as I hadn’t noticed. My method above is deprecated based on the recent release, because Phil and company have made some nice updates, which I greatly appreciate!

This code example was based on version 3.20 of Mail::IMAPclient from August 2009; imap_data wasn’t available in that release. Secondly, I wouldn’t use imap_data now either because Phil put in idle_data in 3.24, which makes life easier.

You don’t have to use a select style function. See Phil’s example (http://cpansearch.perl.org/src/PLOBBES/Mail-IMAPClient-3.25/examples/idle.pl), which similar to my script (not the above example, the actual mail check script I released later) it just reads the idle_data (mine read the raw socket) and checks the data returned. It’s more encompassing than mine, but works in a very similar fashion, down to checking unseen count.

Cheers, Justin

Comment on this Entry

About This Entry

You are reading "How to work with Mail::IMAPClient IDLE command and Perl socket", and entry posted on 27 August, 2009 and filed under perl, Scripting, Snarl.

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