3

I would like to be able to read incoming mail from a Postfix MTA using a shell script. The shell script should be able to retrieve the mail headers, subject, body, attachments, etc., then mark the mail as read. The messages are stored in the Maildir/ format. When a mail is read in Postfix, it's moved from the Maildir/new folder to the Maildir/cur folder which is helpful to retain as a backup in case a message needs to be reprocessed.

I have googled this extensively but haven't found anything helpful, plenty of examples of how to send mail, but nothing useful to read mail through a script. The mail/mailx command only seems to allow interactive access, there doesn't appear to be an option to use it through a shell script. This only needs to work for one user, since I am using a catchall configuration to catch all incoming mail into a single mailbox, for subsequent processing by the script.

There's always the option of polling the Maildir/new folder for incoming messages using a cronjob or incron but I it would be nice to use Postfix's mail management capabilities as opposed to manually managing the msg files. My script will be local to the Postfix server.

Any suggestions/ideas? thanks.

Edit: Maybe I should mention that I'm not looking for help with the script. I'm looking for some command line tool that can access Postfix Maildir/ msg store and read/do stuff with the msgs and can be invoked in a non-interative manner. In other words basic functionality of the mail tool, but non-interactive.

Jim Walker
  • 321
  • 1
  • 3
  • 10

2 Answers2

3

I found the following:

http://notes-cs.blogspot.in/2013/04/use-command-line-to-read-linux-local.html

This person describes exactly what I was looking for. Pure genius! To capture the essence (everything below is from the link above):

Print all email to STDOUT:

$ echo "type *" | mail

$ echo "type 1" | mail   # print the first email to stdout

$ echo "type 3-5" | mail # print the emails from 3 to 5

Check if mail box is empty (i.e. "No mail for [username]" is found):

$ echo q | mail 2>&1 | grep "No mail for [username]"

Purge the mail box:

$ echo "d *" | mail

$ echo "d 3" | mail     # Delete the 3rd email

Save all emails in a text file:

$ echo "s * test.txt" | mail

Save emails between a range in a file:

$ echo "s 3-6 test.txt" | mail # this will save email from #3 to #6 to the file test.txt

Read one email from mailbox:

$ echo 1 | mail # Read the first mail from mail box:

$ echo 5 | mail # Read the 5th email from mail box: 

$ echo 6 | mail

If there is no 6th mail from mail box. It will prompt you below error:

6: Invalid message number

The error message "Invalid message number" tells you that there is no 6th email in the mailbox. If the 5th email is successfully returned. You can treat the error message "Invalid message number" as end of mailbox just like the EOF of a file. Combined this with a loop, you can browse thru all the emails inside the mailbox.

Jim Walker
  • 321
  • 1
  • 3
  • 10
  • Do you know how to extract specific parts like the subject, from, to, body, etc...? – IMTheNachoMan May 07 '16 at 14:50
  • Since I wrote this, I mostly stopped using shell script for stuff like this, there are much better options. For e.g. python has ready made libraries to read and parse messages stored in Maildir format. Other than string parsing, I don't know of any straightforward way to get the header information using shell script. – Jim Walker May 08 '16 at 23:53
2

Your Google Fu is lacking.

One easy solution is a sendmail style ~/.forward file where you pipe | the message directly to your script, before it even gets written to your Mailbox. Your script then does its thing and writes the mail mesage to disk afterwards.

Similarly but you get a bit more flexibility when you configure procmail as the mail delivery agent and set up a ~/.procmailrc to forward the messages to your script.

The alternative is to install an IMAP or POP3 daemon and use fetchmail to poll your mailbox and read any new messages and hand them off to your script.

HBruijn
  • 77,029
  • 24
  • 135
  • 201
  • My bad, I should have clarified I looked at both the .forward and procmail options. My concerns with both is that the outcome is no different from having incron poll the Maildir/new directory and call my script when a new msg file appears. As mentioned in my post, I would like to be able to use Postfix's msg file management capabilities which would not be possible in either of these solutions since the msg file would never make it to Maildir/. – Jim Walker Sep 01 '14 at 14:58
  • Another concern is that when there is deluge of msgs coming in (as is expected in this case), the script might be busy processing previous msgs (all these msgs will contain attachments, which need to be decoded, compressed, in other words 'processed', then stored in a database) while Postfix will make call after call to the same script resulting in database locks, cpu spikes and all such nasty stuff. I would rather be able to pick and choose how and in what order I process the msgs. thanks. – Jim Walker Sep 01 '14 at 15:02
  • Yes, POP3/IMAP are definitely options. I was hoping that if the mail command can read/manage mail locally, there would be something similar and lightweight that I could use without installing another daemon to manage. – Jim Walker Sep 01 '14 at 15:09