Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked
 
PerlMonks  

Read and manage IMAP mails for me

by Discipulus (Canon)
on Jan 30, 2023 at 12:17 UTC ( [id://11150032]=CUFP: print w/replies, xml ) Need Help??

Hello community!

Here you have my recent project using Mail::IMAPClient intended to manage some of my incoming emails. It is able to speak too, but the current speaking ability is provided by Win32::SAPI5 so if you want to use on other platforms, just modify the small voice sub at the end of the program (and lines 8 and 22).

The core of this simple client is the infinite while (1) loop at line 135: an incoming message will be passed to process_message (line 164).

Here in the process_message sub I put some simple example of managing emails: extract the sender (both address and display name), subject and body and some IMAP operation: mark as read, move the message.. modify to your needs.

On windows and using the SAPI voice this program will use the system default voice: you can modify it under control panel -> Speech recognition -> properties (or somthing like that.. you can figure it).

The program handles two signals: BREAK to show the current status of the program and, more important, INT to premit the IMAP logout and so a clean exit.

Here a small example of session:

shell>perl imap-monitorV5PM.pl -u user@example.com -s email.example.co +m -p 993 -ssl 1 -i 5 Enter password for user@example.com on email.example.com VOICE: user@example.com succesfully authenticated on email.example.com + port 993. Checking INBOX for incoming messages every 5 seconds. CTRL-C to exit the program permitting the IMAP logout CTRL-BREAK to review the current status of the program Tabella codici attiva: 1252 + # I press CTRL-BREAK ====================================================================== imap-monitorV5PM.pl PID 5052 Mon Jan 30 12:33:45 2023 - email.example.com connected checked messages: 3 ====================================================================== + # a new message triggering default rule ====================================================================== Mon Jan 30 12:47:29 2023 ====================================================================== VOICE: Default rule. New message from: Johann Sebastian Bach. Subject: + Listen to my new album! ====================================================================== + # I press CTRL-C Logging out.. VOICE: IMAP logout.. Exiting..

..and obviously the code:

use strict; use warnings; use Mail::IMAPClient; use Term::ReadKey; use Getopt::Long; use Encode qw(decode encode); use Win32::SAPI5; use utf8; my $VERSION = 5; my $user; my $server; my $port; my $ssl = 0; my $imap_folder = "INBOX"; my $sleep = 60; my $debug = 0; my $substr = 500; # used to cut body_string my %seen; # take count of already seen messages my $voice = Win32::SAPI5::SpVoice->new(); $|++; GetOptions ( "u|user=s" => \$user, "s|server=s" => \$server, "p|porta=i" => \$port, "ssl=i" => \$ssl, "f|folder=s" => \$imap_folder, "i|interval=i" => \$sleep, "debug" => \$debug, "substring=i" => \$substr, ) or show_help(); sub show_help{ print <<EOH; $0 usage: $0 -user LOGIN -server SERVER -port N [ -ssl 0|1 -folder FOLDER +-interval SECONDI --substring --debug] -u -user username to authenticate on the given server (REQU +IRED) -s -server IMAP server to connect to (REQUIRED) -p -port port used by the server for IMAP connections (REQU +IRED) -ssl use or not SSL to connect (0 or 1 - default 1) -f -folder IMAP folder to check (default: "INBOX") -i -interval seconds between checks (default 60) -substring how many bytes of mail body to print on screen (de +fault 500) -d -debug extra debug output EOH exit; } # check of required arguments my %check = (user=>$user,server=>$server,port=>$port); foreach my $need ( keys %check ){ unless ( defined $check{$need} ){ warn "\nPlease provide the parameter: $need"; show_help(); } } # gently ask for password print "Enter password for $user on $server\n"; my $password; ReadMode('noecho'); $password = ReadLine(0); chomp $password; ReadMode 'normal'; # the IMAP client init my $imap = Mail::IMAPClient->new( Server => $server, User => $user, password => $password, Port => $port, Ssl=> $ssl, Uid=> 1, ) or die "IMAP Failure: $@"; $imap->Peek(1);# do NOT mark as read when handling messages $imap->select( $imap_folder ) or die "IMAP Select Error for imap folde +r [$imap_folder]: $@"; # check the connection if ( $imap->IsConnected() ){ print "FOLDERS\n\t",join( "\n\t", $imap->folders ), "\n" if $debug +; voice("$user succesfully authenticated on $server port $port. ". "Checking $imap_folder for incoming messages every $sleep seco +nds."); } else{ print $imap->LastError(); die; } # useful to print something in cmd.exe defaulting on codepage 850 print "changing codepage..\n"; system (1, 'chcp 1252'); print "\n\nCTRL-C to exit the program permitting the IMAP logout\n"; print "CTRL-BREAK to review the current status of the program\n"; # Handle Ctrl-C $SIG{INT} = sub{ print "\n\nLogging out..\n"; voice("IMAP logout..\n"); $imap->logout(); print "Exiting..\n"; exit; }; # Handle Ctrl-Break $SIG{BREAK} = sub{ print '=' x 70, "\n"; print "$0 PID $$\n"; print scalar localtime(time)," - $server ",($imap->IsConnected() ? + 'connected' : 'NOT connected'),"\n"; print "checked messages: ", scalar keys %seen,"\n"; print '=' x 70, "\n"; }; ################################################################### # checking for new messages infinite loop ################################################################### my $now = time; %seen = map { $_ => 1} $imap->sentsince($now); while (1){ my $attempts = 1; my $max_attempts = 12; while ( !$imap->noop ){ print "Reconection retry $attempts..\n"; $imap->reconnect; if( $imap->IsConnected() ){ print "Reconnected succesfully!\n"; last; } else{ sleep 10; die "Impossible to reconnect: $@" if $attempts == $max_att +empts; $attempts++; } } my @msgs = $imap->sentsince($now); foreach my $msg (@msgs){ next if $seen{$msg}; $seen{ $msg }++; process_message( $msg ); } sleep 1 for 1..$sleep; $now = time; } ################################################################### # handling messages ################################################################### sub process_message{ my $msg = shift; # extract some mail details $imap->get_header( $msg, "From" ) =~ /^(.*)\s<(.*)>$/; my $from_name = $1; my $from_addr = $2; my $subj = decode('MIME-Header', $imap->get_header( $msg, "Subjec +t" )); # some decoration print '=' x 70, "\n"; print scalar localtime(time),"\n"; print '=' x 70, "\n"; ##################################### # RULES ##################################### # Flag the message and print subj and part of the body if( $from_addr eq 'larry.wall@example.com' or $subj =~ /^from larry/i ){ # say something fun voice("Larry wrote you!"); # set the Flagged (=important, yellow star in thunderbird) + $imap->set_flag("Flagged",$msg); print "SUBJECT: $subj\nBODY:\n". # cut the body as per --substring paramenter substr(decode('MIME-Header', $imap->body_string( $msg +) ),0, $substr),"\n"; } # mark as read and move it SOMEWHERE # NOTE: this moves the message into INBOX/SOMEWHERE and if the fol +der does not exists # it creates it for you (you might need to 'subscribe' it in order + to see the message) elsif( $from_addr =~ /perl.org$/ ){ voice("New mail from perl.org"); # mark as read $imap->set_flag("Seen",$msg); # move it my $newmsgID = $imap->move( 'INBOX/SOMEWHERE', $msg )or die "C +ould not move: $@\n"; # expunge make effective the move $imap->expunge; # $newmsgID must be valid print "DEBUG: message moved\n" if $debug and $newmsgID; } # DEFAULT RULE else{ voice( "Default rule. New message from: $from_name. Subject: $ +subj" ); } # With the IMAP protocol you can manage five flags : # # \Seen: Message has been read # \Answered: Message has been answered # \Flagged: Message is marked as “flagged” for urgent/special atte +ntion # \Deleted: Message is marked as “to be deleted”. # Note that the actual removal takes effect when the expunge() +function is called, # when you switch the mailbox, or close the connection. # This flag is already added by the delete() function # \Draft: Message has not completed composition (marked as a draft +). # # use them as in (leading slash is optional) # $imap->set_flag("Seen",$msg); # # BE AWARE: if you omit $msg like in $imap->set_flag("Seen") it wi +ll be interpreted as $imap->set_flag("Seen", 'ALL') # THE ABOVE IS TRUE ALSO FOR THESE METHODS: # # bodypart_string # message_uid # body_string # get_bodystructure # get_envelope # fetch_hash (and so also the migrate methods) # flags # parse_headers # size # # https://github.com/plobbes/mail-imapclient/issues/4 print '=' x 70, "\n"; } sub voice{ my $txt = join ' ',@_; $voice->Speak($txt); print "VOICE: $txt\n"; }
L*

There are no rules, there are no thumbs..
Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.

Replies are listed 'Best First'.
Re: Read and manage IMAP mails for me
by cavac (Parson) on Mar 14, 2023 at 15:25 UTC

    Getting the computer to read out (parts of) emails sounds terrifying and hilarious at the same time. Bonus points if you can get it to sound like HAL9000.

    A new business message marked "important" has arrived from Nigeria. Me +ssage as follows: I am Dr. Bakare Tunde, the cousin of Nigerian Astronaut, Air Force Maj +or Abacha Tunde. He was the first African in space when he made a secret flight to the Salyut 6 space station in 1979. He was on a lat +er Soviet spaceflight, Soyuz T-16Z to the secret Soviet military space station Salyut 8T in 1989. He was stranded there in 1990 when th +e Soviet Union was dissolved. His other Soviet crew members returned to earth on the Soyuz T-16Z, but his place was taken up by re +turn cargo. There have been occasional Progrez supply flights to keep him going since that time. He is in good humor, but wants to c +ome home. In the 14-years since he has been on the station, he has accumulated f +light pay and interest amounting to almost $ 15,000,000 American Dollars. This is held in a trust at the Lagos National Savings and Tru +st Association. ...

    PerlMonks XP is useless? Not anymore: XPD - Do more with your PerlMonks XP
Re: Read and manage IMAP mails for me
by Bod (Parson) on Mar 14, 2023 at 23:53 UTC

    It's a pity I've not been able to get Perl to run on my Android mobile even with Termux.

    Driving a good time to listen to emails being read out as one's body is occupied but the mind is mostly free. I've written an Android app to read emails to me whilst driving but it is not very good and needs work before it is properly usable. The problem is that it's in Java...if only I could get Perl on Android...

    Thanks Discipulus for re-igniting that idea...I shall give your code a try...

        Thanks for that LanX

        I haven't looked at Termux for a while although it's been installed for an age. I shall look again soon and see if I can use it to run a useful application...

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: CUFP [id://11150032]
Approved by Corion
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others wandering the Monastery: (4)
As of 2024-04-25 12:33 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found