jBiff
, my IMAP-to-XMPP thingee, comes in. I've even taken to using the web interfaces instead of Thunderbird on occasion. All is well in the world.But there's a problem.
Lists. Lists and filters. Filtering lists. ( That makes it one problem again. )
I'm used to using
slocal
or procmail
on Unix machines to filter as the mail comes in. I'm not nearly as happy with the interface to filtering in Gmail, but I do love the result, which is a cleaner inbox.My work mail has filtering that's enabled when you use the web interface. I don't use the web interface often, and when I have all my filters in Thunderbird, nothing is filtered when I use the web. What I needed is a means to write my filters outside of a mail client and have them run regularly, so that the state of the inbox is always as it should be.
So, I wrote
imap_filter.pl
. It needs to be cleaned up a bit, and it is not feature-complete, but I'm able to move mail based on many good things, so I'm at a done point.- #!/usr/bin/perl
- use 5.010 ;
- use strict ;
- use warnings ;
- use lib '/home/jacoby/bin' ;
- use Carp ;
- use Data::Dumper ;
- use Getopt::Long ;
- use IO::Socket::SSL ;
- use IO::Interactive qw{interactive} ;
- use Mail::IMAPClient ;
- use IdentConf ':all' ;
- use subs qw{ imap_part xmpp_part } ;
- $Data::Dumper::Indent = 1 ;
- my $debug ;
- my $imap_identity ;
- #methods
- my @from ;
- my @to ;
- my @cc ;
- my @subject ;
- my @to_or_cc ; # don't use or yet.
- my $age = 0 ;
- #actions
- my $move ; #move to dir
- my $forward ; #forward to this address
- my $delete ; #delete this file
- my $read ;
- my $unread ;
- GetOptions(
- 'imap=s' => \$imap_identity,
- 'from=s' => \@from,
- 'to=s' => \@to,
- 'cc=s' => \@cc,
- 'or=s' => \@to_or_cc,
- 'subject=s' => \@subject,
- 'age=i' => \$age,
- 'move=s' => \$move ,
- 'delete' => \$delete ,
- 'read' => \$read ,
- ) or exit( 1 ) ;
- exit if !defined $imap_identity ;
- exit if length $imap_identity < 1 ;
- for my $a ( @to_or_cc ) {
- push @to, $a ;
- push @cc, $a ;
- }
- my $filter ;
- $filter->{ from } = \@from ;
- $filter->{ subject } = \@subject ;
- $filter->{ to } = \@to ;
- $filter->{ cc } = \@cc ;
- $filter->{ age } = $age ;
- $filter->{ move } = $move ;
- $filter->{ read } = $read ;
- $filter->{ delete } = $delete ;
- imap_part $filter ;
- exit ;
- # ====================================================================
- #
- # connect to and search your mail server via IMAP
- #
- # ====================================================================
- sub imap_part {
- my ( $filter ) = @_ ;
- say { interactive } Dumper $filter ;
- my %creds = get_credentials( 'imap', $imap_identity ) ;
- my $socket = IO::Socket::SSL->new( PeerAddr => $creds{ server },
- PeerPort => $creds{ port },
- ) or die "socket(): $@" ;
- my $client = Mail::IMAPClient->new( Socket => $socket,
- User => $creds{ username },
- Password => $creds{ password },
- ) or die "new(): $@" ;
- if ( $client->IsAuthenticated() ) {
- $client->select( $creds{ directory } )
- or die "Select '$creds{directory}' error: ",
- $client->LastError, "\n" ;
- my $i = 1 ;
- for my $msg ( reverse $client->messages ) {
- my $flag = 0 ;
- my $from = $client->get_header( $msg, 'From' ) ;
- my $sender = $client->get_header( $msg, 'Sender' ) ;
- my $date = $client->date( $msg ) ;
- my $to = $client->get_header( $msg, 'To' ) ;
- my $cc = $client->get_header( $msg, 'Cc' ) ;
- my $subject = $client->subject( $msg ) ;
- my @flags = $client->flags( $msg ) ;
- my $seen = 0 ; $seen = 1 if grep m{/Seen}mx , @flags ;
- next if grep m{\Deleted}mx , @flags ;
- # Subject
- if ( scalar @{ $filter->{ subject } } > 0 ) {
- for my $f ( $filter->{ subject } ) {
- my $ff = $$f[ 0 ] ;
- $subject =~ m{($ff)}mix ;
- say $1 if defined $1 ;
- $flag++ unless defined $1 ;
- }
- }
- # From
- if ( scalar @{ $filter->{ from } } > 0 ) {
- for my $f ( $filter->{ from } ) {
- my $ff = $$f[ 0 ] ;
- $from =~ m{($ff)}mix ;
- $flag++ unless defined $1 ;
- }
- }
- # To
- if ( scalar @{ $filter->{ to } } > 0 && ! defined $to ) {
- $flag++ ;
- }
- if ( scalar @{ $filter->{ to } } > 0 && defined $to ) {
- for my $f ( $filter->{ to } ) {
- my $ff = $$f[ 0 ] ;
- $to =~ m{($ff)}mix ;
- $flag++ unless defined $1 ;
- }
- }
- # Cc
- if ( scalar @{ $filter->{ cc } } > 0 && ! defined $cc ) {
- $flag++ ;
- }
- if ( scalar @{ $filter->{ cc } } > 0 && defined $cc ) {
- for my $f ( $filter->{ cc } ) {
- my $ff = $$f[ 0 ] ;
- $cc =~ m{($ff)}mix ;
- $flag++ unless defined $1 ;
- }
- }
- # Age
- #GOT NADA
- next if $flag ;
- if ( 1 ) {
- my $title = 'New mail from ' . $from ;
- my $body = $subject ;
- $body = join q{"}, '', $body, '' ;
- #say { interactive } "$title - $body" ;
- say { interactive } $i++ . "\t" . '=' x 40 ;
- say { interactive } $subject;
- say { interactive } 'From: ' . $from ;
- say { interactive } ' Sender: ' . $sender if $sender ;
- say { interactive } ' To: ' . $to if $to ;
- say { interactive } ' Cc: ' . $cc if $cc ;
- say { interactive } ' Date: ' . $date ;
- say { interactive } join ' ' , ' ' , @flags ;
- if ( $filter->{ move } ) {
- my $move = $filter->{ move } ;
- say { interactive } ' Move: ' . $move ;
- my $newUid = $client->move( $move , $msg )
- or die "Could not move: $@\n";
- }
- say { interactive } '' ;
- }
- }
- $client->logout() ;
- }
- else {
- say { interactive } 'FAIL ' . $! ;
- }
- }
- # --------------------------------------------------------------------
No comments:
Post a Comment