5 =head1 NAME $RCSfile: announceEmail.pl,v $
7 Monitors an IMAP Server and announce incoming emails by extracting the subject
8 line and from line and then pushing that into "GoogleTalk".
16 Andrew DeFaria <Andrew@DeFaria.com>
24 Thu Apr 4 13:40:10 MST 2019
28 $Date: 2019/04/04 13:40:10 $
34 Usage: announceEmail.pl [-usa|ge] [-h|elp] [-v|erbose] [-de|bug] [-da|emon]
35 [-use|rname <username>] [-p|assword <password>]
39 -usa|ge: Print this usage
41 -v|erbose: Verbose mode (Default: -verbose)
42 -de|bug: Turn on debugging (Default: Off)
43 -da|emon: Run in daemon mode (Default: -daemon)
44 -use|rname: User name to log in with (Default: $USER)
45 -p|assword: Password to use (Default: prompted)
46 -i|map: IMAP server to talk to (Default: defaria.com)
50 This script will connect to an IMAP server, login and then monitor the user's
51 INBOX. When new messages arrive it will extract the From address and Subject
52 from the message and compose a message to be used by "Google Talk" to announce
53 the email. The message will be similar to:
55 "<From> emailed <Subject>"
68 use lib "$FindBin::Bin/../lib";
74 my $defaultIMAPServer = 'defaria.com';
80 usage => sub { pod2usage },
81 help => sub { pod2usage(-verbose => 2)},
82 verbose => sub { set_verbose },
83 debug => sub { set_debug },
85 username => $ENV{USER},
86 password => $ENV{PASSWORD},
87 imap => $defaultIMAPServer,
92 $log->msg("Turning off debugging");
95 $log->msg("Turning on debugging");
102 $SIG{USR1} = \&interrupted;
107 $log->msg($msg) if get_debug;
113 $IMAP->select('inbox') or
114 $log->err("Unable to select inbox: " . get_last_error(), 1);
116 return map { $_=> 0 } @{$IMAP->search('not', 'seen')};
120 $log->msg("Connecting to $opts{imap} as $opts{username}...", 1);
122 $IMAP = Mail::IMAPTalk->new(
123 Server => $opts{imap},
124 Username => $opts{username},
125 Password => $opts{password},
126 ) or $log->err("Unable to connect to IMAP server $opts{imap}: $@", 1);
128 $log->msg(' connected');
130 # Focus on INBOX only
131 $IMAP->select('inbox');
133 # Setup %unseen to have each unseen message index set to 0 meaning not read
135 %unseen = unseenMsgs;
142 # First close and reselect the INBOX to get its current status
143 debugit "Reconnecting to INBOX";
145 $IMAP->select('INBOX')
146 or $log->err("Unable to select INBOX - ". $IMAP->errstr(), 1);
148 # Go through all of the unseen messages and add them to %unseen if they were
149 # not there already from a prior run and read
150 my %newUnseen = unseenMsgs;
152 # Now clean out any messages in %unseen that were not in the %newUnseen and
153 # marked as previously read
155 if (defined $newUnseen{$_}) {
157 delete $newUnseen{$_};
164 debugit "Processing newUnseen";
165 for (keys %newUnseen) {
168 my $envelope = $IMAP->fetch($_, '(envelope)');
169 my $from = $envelope->{$_}{envelope}{From};
170 my $subject = $envelope->{$_}{envelope}{Subject};
171 $subject //= 'Unknown subject';
173 # Extract the name only when the email is of the format "name <email>"
174 if ($from =~ /^"?(.*?)"?\s*\<(\S*)>/) {
175 $from = $1 if $1 ne '';
178 if ($subject =~ /=?\S+?(Q|B)\?(.+)\?=/) {
179 $subject = decode_base64($2);
182 # Google Talk doesn't like #
186 debugit "Speaking message from $from";
187 my $logmsg = "From $from $subject";
189 my $msg = "Message from $from... " . quotemeta $subject;
197 my $cmd = "/usr/local/bin/gt \"$msg\"";
199 my $hour = (localtime)[2];
201 # Only announce if after 6 Am. Note this will announce up until
202 # midnight but that's ok. I want midnight to 6 Am as silent time.
204 my ($status, @output) = Execute $cmd;
207 $log->err("Unable to execute $cmd" . join("\n", @output));
219 $IMAP->quit if $IMAP;
221 $log->msg("$FindBin::Script ending!");
238 unless ($opts{password}) {
239 verbose "I need $opts{username}'s password";
240 $opts{password} = GetPassword;
243 $opts{debug} = get_debug;
245 EnterDaemonMode if $opts{daemon};
249 timestamped => 'yes',
255 my $msg = "Now monitoring email for $opts{username}\@$opts{imap}";
259 my $cmd = "/usr/local/bin/gt \"$msg\"";
261 my ($status, @output) = Execute $cmd;
263 $IMAP->idle(\&MonitorMail);