Perl: Read email and use message content as stdin for an excel update - excel

I am looking for some help with starting a Perl script. I'm relatively inexperienced with Perl so help would be appreciated :)
Basically, want to start a project to write a script that helps keep up to date with hours I have been working. Basically I would like the script to E-mail (automated using cron) me reminding me to send my hours each day, then I send an e-mail back with the message as something like
"03/02/14 7.30 18.30"
The script will then read the data and update an excel spreadsheet keeping a log of hours.
I know how to do everything except having the script read an e-mail. I have been doing research into MIME::* MAIL::* but I'm not entirely sure which package would be the best and how to actually go about it.

As #mpapec suggested you could read email using IMAP or a local mailbox on a linux box.
In windows you could use OLE and read emails in an outlook: Perl: Win32::OLE and Microsoft Outlook - Iterating through email attachments efficiently
You could read emails on exchange in this way: http://metacpan.org/pod/Email::Folder::Exchange
If I were you I would use IMAP to access emails. It is platform independent and not too hard to use (I used it in the past and it was reliable).
http://metacpan.org/pod/Net::IMAP::Client
my $imap = Net::IMAP::Client->new(
server => 'mail.you.com',
user => 'USERID',
pass => 'PASSWORD');
# select folder
$imap->select('INBOX');
#newest first
my $messages = $imap->search({
FROM => 'you',
SUBJECT => 'your email subjet',
}, [ '^DATE' ]);
# fetch full message (newest)
my $data = $imap->get_rfc822_body($messages->[0]);
#process
store_data_in_excel($data);
#move to archive
$imap->copy([$messages->[0]], 'Archive');
$imap->add_flags(\#msg_ids, '\\Deleted');
$imap->expunge;

Related

Using flock to lock file for X time

I am a Linux novice and currently developing a security system using Raspberry Pi 3 and MotionEye. To get notifications via e-mail, I am attempting to create a custom shell script that will send an e-mail if there is motion, lock for X minutes, then send another e-mail if there is still motion. However, I am having some difficulties.
I created a simple Python script named "send_email.py" using SMTP that works perfectly fine for sending e-mails when I execute it via command line.
The shell script (named "flock_email.sh") is where I run into troubles in a few regards:
Whenever I run flock_email.sh, it completely overwrites send_email.py. I have tried to change file permission so it is only executable by the user, but it still overwrites.
The flock command/function does not work as I intended or at all. I have looked all over the internet and tried multiple different codes, but none have worked. I have attached my various flock_email.sh scripts I have tried.
Not necessarily a problem, but I am a bit confused on what my "shebang" line should be. For flock_email.sh I have it as "!#/bin/bash", which I believe makes the script it executable, at least according to this. Do I still need to change the permissions via the command "chmod +x flock_email.sh"? The path is /home/pi, which is essentially the main directory of my Pi.
The different solutions I have tried:
In flock_email.sh, I have tried to directly change the file permissions to read-only instead of using flock, having it sleep, then changing the permissions back to allow execution of the file.
Multiple flock_email.sh implementations, as attached.
To summarize:
I need to execute send_email.py before locking the file flock_email.sh.
Once locked, it needs to stay locked for X time.
Does anyone have any pointers or suggestions? I have spent well over 15 hours tinkering with this and feel like I have gotten nowhere!
send_email.py:
#!/usr/bin/env
import smtplib
def send_email():
content = "Message I want to send to specified e-mail."
sender = "e-mail account that will send message"
pword = "password of sender"
receiver = "e-mail account that will receive message"
mail = smtplib.SMTP("smtp.gmail.com",587)
mail.ehlo
mail.starttls()
mail.login(sender,pword)
mail.sendmail(sender,receiver,content)
mail.close()
send_email()
flock_email.sh (1):
#!/bin/bash
(
python /home/pi/send_email.py
flock -e 200
sleep [time in seconds]
)
flock_email.sh (2):
#!/bin/bash
(
python /home/pi/send_email.py
exec 3>/home/pi/send_email.py
flock -x 3
sleep [time in seconds]
exec 3>&-
)
flock_email.sh (3):
#!/bin/bash
python /home/pi/send_email.py
chmod 444 /home/pi/send_email.py # modify to read only for all
sleep [time in seconds]
chmod 755 /home/pi/send_email.py # modify to rwx for owner, r-x for others
The reason why man flock and all posts say to use > is because you're supposed to use a dedicated lock file, typically in /var/lock:
#!/bin/bash
exec 3> /var/lock/motionmail
flock -ne 3 || exit
python /home/pi/send_email.py
sleep 3600
This additionally fixes you sending your email regardless, before you ever check the lock, and aborts new emails instead of queueing them all up.
You choose the lock file name based on the scope you want your lock to have:
If you only want one email per hour, you can use something like /var/lock/motionmail because there's just one per system.
If you want one email for each user per hour, you can use $HOME/.motionmail.lock because there's just one per user.
You can use /home/pi/send_email.py if you want with <, but this implies that you want one email per hour not only for each user, programming language and script copy, but also every time you hit save and replace the file with your editor*
* Editors differ in whether they replace or overwrite a file

Perl - How to send local mail?

I would like to integrate the following terminal command into a Perl script.
Terminal command:
mutt -s "User Monitoring" -a "/home/mipa/Documents/System_Monitoring/protocol_name.csv" -- mipa#localhost.localdomain
The command sends local mail containing a file attachment to a user on the same system.
I have a small problem with the command though. It does seem to require more user interaction than just the command listed here. The command requires the user to follow a menu to confirm the values and hit the "y" key to send.
My question here is two-folded. Is there a similar mail command that does not require user interaction and works by just following a single command with predefined flags? And how would I integrate this command into a Perl script where I would be able to choose the file name, and the receiving user followed by issuing the command?
Any guidance regarding a possible solution is highly appreciated.
there are a few ways to send command line emails in Linux: How do I send a file as an email attachment using Linux command line?
why is the -- in your command? that maybe confusing mutt.
https://unix.stackexchange.com/questions/108916/automatically-attach-a-file-to-a-mail-with-mutt has a few more suggestions for sending mail with mutt.
I prefer to use MIME::Lite to send emails, rather than spawning an external command, which avoids the problems you are having. MIME::Lite is able to handle sending emails with attachments.
Here is a quick example:
#!/usr/bin/perl
use strict;
use MIME::Lite;
my $msg = MIME::Lite->new(
To => 'foo.bar#foobar.com',
Subject => 'Test message with attachments',
Type => 'multipart/mixed'
);
$msg->attach(
Type => 'TEXT',
Data => "Here's the file you wanted"
);
$msg->attach(
Type => 'image/png',
Path => 'somefile.png',
Filename => 'somefile.png',
Disposition => 'attachment'
);
$msg->send();
This would send a message containing a small amount of text and a single attachment.
There are a lot more examples given in the POD for MIME::Lite.

OfflineIMAP and Mutt with Gmail's All Mail folder

OfflimeIMAP
I am trying to sync my Gmail - All Mail folder with idlefolders through offlineimap. My .offlineimaprc config has this -
idlefolders = ['INBOX', '[Gmail].All Mail']
My name of my All Mail folder in .mail (where my mailboxes are) looks like
drwx------ 5 ry ry 4096 Oct 12 18:13 [Gmail].All Mail
I think the name is wrong in idlefolders. I see a lot of people online using [Gmail]/All Mail.
My INBOX folder sync fine but All Mail does not.
MUTT
Also trying to set a macro shortcut to All Mail in .muttrc I have -
macro index ga "<change-folder> =[Gmail].All Mail<enter>"
This does not work, but my macro for INBOX does work
macro index gi "<change-folder> =INBOX<enter>"
What's wrong? How should I call my All Mail folder?
for my Mutt 1.5.21, percent encoding works:
macro index ga "<change-folder>=[Gmail]/All%20Mail<enter>"
I think the problem here is the whitespace in the folder. Possible solutions:
Update: As winchendonsprings pointed out, there is a way to escape the whitespace in the folder name. Now we can use a macro to change to All Mail:
bind editor <space> noop
macro index ga "<change-folder>=[Gmail].All Mail<enter>" "Go to all mail"
You use a name transalation to create mailboxes without a
whitespace as described in the
documentation.
For example the translation could look like this:
nametrans = lambda x: re.sub('\[|\]|\s', '_', x)
You should make sure, as the documentation states, that no folder
ends up with the same translated name. You can check this by running
offlineimap with --info.
Another possible solution could be, to register your mailboxes and
simply use a macro to toggle between the index and your list of configured
mailboxes, eg. in your .muttrc:
mailboxes =[Gmail].All\ Mail =[Gmail].Important =[Gmail].Starred
macro index <left> ':mailboxes <enter>c?<toggle-mailboxes>
That provides the benefit that mutt monitors your local mailbox and
tells you if you've got new mail. You can even automate this if you want. Examples can be found here.
Another terrible solution is to just use <complete> to avoid typing a literal space:
macro index ga "<change-folder>=[Gmail]/All<complete><enter>"

IMAP array values changing spontaneously - PHP

My company uses script-generated emails to correspond with clients. Until now, we've had to manually sort through these emails, look up client info, print and file them. I'm writing a script that does this automatically and it was working fine until 10 minutes ago when Google stopped sending the subject with imap_fetch_overview().
Here's how I'm doing it:
$msgov=imap_fetch_overview($inbox,$uid,FT_UID);
$msgsub= $msgov[0]->subject;
$msgfr= $msgov[0]->from;
$msgid= $msgov[0]->uid;
$message = imap_fetchbody($inbox,$uid,1,FT_UID);
//echo message info, then message
echo "...";
And that worked fine until about 10 minutes ago when I started getting this error: Notice: Undefined property: stdClass::$subject in C:\wamp\www\gmil\index.php on line 113
So I proceed to echo var_dump($msgov); and suddenly it's not showing the subject anymore.. According to The Manual it should be giving me the subject. Am I doing something wrong or am I just unlucky enough to be doing this at the exact time Google decided to stop sending it?
I'm dumb.
After one message not didn't contain a subject, it stopped checking for that value in all subsequent loops. I solved it like this:
if(isset($overview[0]->subject)){$sub=$overview[0]->subject;}else{$sub="No Subject";}
and then called $sub instead of $overview[0]->subject.

Reading emails with groovy (Java Mail)

I am using groovy in order to access gmail and read the Inbox. It is regular JavaMail and will not describe it here.
So for simplicity, after I connect to the store, I use this:
folder.open(Folder.READ_ONLY)
folder.messages.each { msg ->
...
doSomething with msg
...
}
this is working fine.
However I have a performance issue. Sometimes messages[] could be big. Some folders contain more than 1000 messages, and checking them all takes time.
I am looking for a quicker way to get only those emails that are the most recent (for example messages from the last 5 days or something like that)
of course I have the date information in each msg and I could do my comparison, but this is not efficient since it will loop through the entire collection.
Is there a better way to get those messages?
If you have JavaMail issue a SEARCH command with the criterion SINCE 04-JAN-2011, you'll get back the set messages in the currently-selected folder delivered since January 4th. (SENTSINCE 04-JAN-2011 will do the same thing, only based on the "Date" message header.)
Something along the lines of this:
folder.search(new ReceivedDateTerm(ComparisonTerm.GE, sinceDate));

Resources