2006-10-15

Catharsis (flushgmail)

When I got my gmail account I read the ad saying "this is a fantastic spot to subscribe to all your favourite mailing lists and never delete any email EVER". Saw I said, "ok, let's do that". I started subscribing to a few mailing lists (with lots and lots of traffic) and what do you know? 22k email messages on the first month. So I said "my bad, let's delete all these messages and I'll just read my news from tin as usual". But I found no way of doing this.

Months and years passed and not a single time did I use this account. Why? Because it was muffled with all these garbage messages. "Time to change this", Yoda said. So I looked at fetchmail's manpage to see if I could get rid of all messages in a POP3 mailbox (yes gmail now gives you POP3-SSL access). Guess what? You can't do this without retrieving part of the messages. I resorted to something like this:

fetchmail -v -a --ssl -p POP3 -u account@gmail.com pop.gmail.com --bsmtp /dev/null


"Oh, such inefficiency!" cried the young padowan and ran towards the masters.

I say, since we're still on Catharsis weekend, let's do a proper flush for gmail :)


flushgmail.pl
---------------------------------------------------------------
#!/usr/bin/perl -w

use Term::ReadPassword;
use Mail::Transport::POP3;

my $gmail_server = "pop.gmail.com:995";
my $stunnel_pid_file = "/tmp/flushgmail_stunnel4.pid";

die "usage: flushgmail.pl <localport>\n" unless(@ARGV == 1);

my $localport = shift @ARGV;

print "Enter gmail username: ";
my $username = <>;
die "error: no username provided!\n" unless defined $username;
chomp($username);

my $password = read_password(' gmail password: ');
die "error: no password provided!\n" unless defined $password;

sub report {
my $msg = shift;
print "flushgmail: $msg\n";
}

sub stunnel_shutdown {
my $msg = shift;
report($msg);
if (-r $stunnel_pid_file){
kill('TERM',`cat $stunnel_pid_file`);
}
}

sub sig_int_catcher {
stunnel_shutdown("stunnel emergency shutdown");
die "flushgmail: caught SIG_INT!\n";
}

$SIG{INT} = \&sig_int_catcher;

stunnel_shutdown("destroying old stunnel instances");

report("spawning new stunnel");
open(STUNNEL, "|stunnel4 -fd 0");
print STUNNEL << "STUNNEL_END_CONFIG";
pid = $stunnel_pid_file
[gmail]
accept = $localport
client = yes
connect = $gmail_server
STUNNEL_END_CONFIG

close(STUNNEL);

my $total_deleted_msgs = 0;
my $run = 1;
while(1){
my $pop3_conn = Mail::Transport::POP3->new(
port => $localport,
hostname => 'localhost',
username => $username,
password => $password);

unless (defined($pop3_conn)){
stunnel_shutdown("emergency stunnel shutdown");
die "error: could not connect to stunnel\n";
}

my $msg_cnt = $pop3_conn->messages;
last if ($msg_cnt == 0);
report("run #$run found $msg_cnt messages");

my @ids = $pop3_conn->ids;
$pop3_conn->deleted(TRUE, @ids);
$pop3_conn->disconnect;
$total_deleted_msgs += $msg_cnt;
++$run;
}

stunnel_shutdown("shutting down stunnel");
report("deleted $total_deleted_msgs messages");


To use the script you'll need Perl modules Mail::Box and Term::ReadPassword, as well as stunnel4 (cause Mail::Box doesn't support SSL natively yet).

If you're wondering why there's a loop around the POP3 connection.. I noticed that each time I connected to gmail, the pop3 server provided me with just a subset of my mailbox (ranging from 500 to 1200 messages) instead of the whole thing. Maybe this is the way gmail organises their mbox'es, in volumes of a certain size..

No comments: