4

I have a (Linux) mail server that consists of postfix for receiving mail, amavisd-new for content filtering (using clamav and SpamAssassin), and dovecot for delivery and IMAP.

I'd like to set things up so that a script is fired off every time an email is delivered to a particular mailbox. The script doesn't necessarily need to know anything about the content or headers of the message. I know of at least a couple of options:

  1. Use postfix's built-in filtering. Set up a header check to reroute any emails destined for this mailbox to my script, which can then pass it back into postfix. The disadvantage here is that it all happens before amavis's filtering, so my script will get fired off even for emails that end up getting blocked before delivery. There may also be performance penalities and risk of lost emails if I don't execute the passage of the email back into postfix properly.

  2. Add my script as a content filter to amavis. This may be an improvement in performance compared to the previous, and just seems like a better place for this. Unfortunately it still suffers from being executed before the go/no-go decision has been made on the message. Additionally, I've not been able to find the amavis documentation detailing how this is actually supposed to be done, and the conf files aren't really conclusive.

Seems like the final dovecot delivery step would be the best place to get only filtered mail, but I'm not sure if there's a way to make that work.

Suggestions? Anything I'm overlooking?

Edit: Forgot to add, I'd like to avoid polling-type solutions (watching logs, IMAP client script, etc.)

glibdud
  • 273
  • 2
  • 12
  • To scan a logfile and act on appropriate patterns therein might be another option. – thrig Sep 24 '15 at 00:13
  • @thrig Thanks for the suggestion. That reminds me of another constraint I forgot to put in... I'd like to avoid polling-type solutions if possible. Will edit it into the question. – glibdud Sep 24 '15 at 00:15

2 Answers2

4

I found another option that may prove to be a good enough solution: hijacking the message as it's passed from postfix to dovecot.

For postfix, I change the following lines in master.cf:

dovecot      unix   -        n      n       -       -   pipe
  flags=DRhu user=vmail:mail argv=/usr/lib/dovecot/dovecot-lda -d $(user)@$(domain)

To:

dovecot      unix   -        n      n       -       -   pipe
  flags=DRhu user=vmail:mail argv=/scripts/emaildeliverycheck.py $(user)@$(domain)

Then create /scripts/emaildeliverycheck.py like the following (Python 3.4):

#!/usr/bin/python3

from sys import argv, stdin, exit
from subprocess import Popen, check_call, CalledProcessError

# Define recipients that should trigger the script here
notifyusers = ('user1@mydomain.com',
               'user2@mydomain.com')

recipient = argv[1]

if recipient in notifyusers:
    # Run the script. Use Popen so that we don't have to wait for the 
    # script to finish
    Popen(['/scripts/myscript.py', recipient])

try:
    # Now pass the email to dovecot-lda. Use check_call because we *do* 
    # want to wait for it to finish
    check_call(['/usr/lib/dovecot/dovecot-lda', '-d', recipient], stdin=stdin)
except CalledProcessError as error:
    # Propagate any error codes back to Postfix
    exit(error.returncode)

Postfix's pipe process passes the email for final delivery to the above script instead of directly to dovecot-lda. The script checks the recipient (passed on the command line, so it doesn't need to look at the message at all) against a list, and fires off another script if there's a match. Then it pipes the message through to dovecot-lda, which shouldn't be able to tell that it's not getting it directly from Postfix, and propagates the exit status back to the pipe process.

Works fine in initial testing. This gets me only post-filtered emails, which is what I'm going for.

glibdud
  • 273
  • 2
  • 12
  • Been watching the logs for a few days, and so far so good. In absence of any better ideas, I'm going with this. – glibdud Sep 27 '15 at 20:20
1

I use procmail as my local delivery agent. This allows extensive filtering using rules applicable to the user. It should be possible to configure postfix to use procmail to do the filtering and, if desired, delivery of the email.

procmail has extensive capabilities to apply filters to headers, content or both. You can use any program as a filter, so your should be able to trigger your script for each email sent to the specified user.

BillThor
  • 27,737
  • 3
  • 37
  • 69