I run a Postfix/Dovecot mail server for personal use. There's only a handful of actual mailboxes, essentially just postmaster@domain.com and username@domain.com.

I frequently use the virtual file to create virtual mailboxes forwarded to username@domain.com. I have a number of these for throwaway accounts like one-time purchases from online stores, online games I want to try without worrying about ongoing spam, etc. To do so I SSH and run the following commands:

sudo vim /etc/postfix/virtual
# add a line that looks like:
# # username_servicename@domain.com      username@domain.com
sudo postmap virtual
sudo service postfix restart

I do this with enough frequency that I'd like to automate the process to some degree. I considered simply writing a shell script that took the virtual mailbox and real mailbox as arguments and made the changes itself, but am hoping for something even more hands off.

I would like to be able to send an email from username@domain.com to some other mailbox on the server with the virtual mailbox name as the body of the message. The issue would be the sudo calls but I can create a new user whose sole responsibility is to handle this which should handle that.

Mostly the question is this: how would I create an event that would be triggered by an email? Is there a service somewhere that does this? Can I configure either Postfix or Dovecot to listen for that email and run commands on that event?

  • Have you checked this link? – kirill-a Jan 12 '15 at 9:54
  • @kirill-a no I hadn't. It looks like that could be purposed to solve this problem, and now I finally have a good reason to learn PHP – Adam Smith Jan 12 '15 at 18:48
  • You do not need to learn PHP: just substitute your own shell script to the PHP script, and you are done. – MariusMatutiae Jan 15 '15 at 14:59
  • @MariusMatutiae if you or kirill-a would like to write up an answer on the topic then (assuming it works) I'll happily award the bounty – Adam Smith Jan 15 '15 at 19:53
  • @kirill-a courtesy ping for my comment, above. – Adam Smith Jan 15 '15 at 19:54

The correct procedure to execute a script (I use a shell script) upon receipt of a mail message is the following. It involves modifying postfix's configuration file, master.cf (which, in my Debian, is located in /etc/postfix) by adding the following line:

 my_shell_script unix - n n - - pipe flags=F user=MY_USERNAME argv=/path/to/my/shell/script ${sender} ${size} ${recipient}

which instructs postfix to run the script (you need to make it executable) when some event occurs.

To specify when to execute the script, you do as follows: suppose you want it to be executed when username@domain.com receives a message. Place the following line

 username@domain.com FILTER my_shell_script:dummy

inside the file /etc/postfix/address.txt; you will need to create a proper database for postfix to use this file, which you accomplish by means of

  postmap /etc/postfix/address.txt

which produces as output a file called /etc/postfix/address.db. Now go back to the /etc/postfix/main.cf file and add the following line:

 smtpd_recipient_restrictions = check_recipient_access hash:/etc/postfix/access, permit_mynetworks, reject_unauth_destination

Now restart postfix,

  postfix reload

and you should be good to go.

  • 2
    Don't you mean 'check_recipient_access hash:/etc/postfix/address' here? You used "access" where I think you meant "address", based on your instructions. – Lee Fuller Jun 22 '16 at 6:06
  • 3
    Is this the same if you are running virtual_mailboxes for various virtual domains? I've followed these instructions verbatim - and if I do not declare a virtual_alias I get a bounce. If I do, it delivers the message to the mailbox but does not trigger the script. – Lee Fuller Jun 22 '16 at 6:12
  • I didn't get this to work. This answer worked: serverfault.com/questions/322657/… – jlh Mar 19 at 8:01

I can see two obvious solutions.

If you are using procmail as the MDA on your server, or are willing to convert to using it, then you can run any arbitrary script on any arbitrary email through procmail's | (pipe) recipe action. It hopefully won't be started as root, but it should be easy to make a script that performs the required magic and which can be invoked passwordless as root by a relevant user. The output of the script could even be fed back into the same email and the email later delivered by making the recipe a filter action.

An alternative (which should require less hands-on maintenance) is to create a single mailbox and configure Postfix's $recipient_delimiter to be something that is not normally used for that purpose; for example, . or -. Note that recipient_delimeter is a server-wide setting. Let's say you set up the mailbox dummy@example.com and set $recipient_delimeter = .. This will then allow dummy.<anything>@example.com which will deliver to the local mailbox corresponding to dummy@example.com. To disable one of these, add dummy.<whatever>@example.com to an appropriate recipient table with a reject action. The downside is that it will be a catch-all mailbox for the prefix, so you would want to make the prefix hard to stumble across by accident or dictionary attacks. The upside is that in the normal case (the sender respects your wishes and does not resell your email address) this approach requires zero maintenance, and you can always change your prefix later and explicitly list those combinations that you want to keep on receiving mail for.

  • I'm not tied to Postfix for any reason other than it's what I have currently. I'd prefer to find a solution that would work with my current MDA/MTA, however. As for delimiter's: I hardly trust that the sender will respect my wishes and not resell my email address, or I'd be giving them the permanent address :) – Adam Smith Jan 12 '15 at 16:43
  • @AdamSmith The difference is, with something like my second alternative, you can disable the address you gave a particular entity without causing problems anywhere else, and the addresses look sensible even to dumb automated verifiers. As for keeping the MDA/MTA, procmail can be used as a drop-in replacement for the Postfix MDA; no need to replace Postfix as your MTA. – a CVn Jan 12 '15 at 20:15
  • procmail is not maintained any more: see lwn.net/Articles/416901, an article with title: Reports of procmail's death are not terribly exaggerated. Better play it safe, and follow @kirill-a's suggestion. – MariusMatutiae Jan 15 '15 at 15:01
  • procmail is still plenty used, and (IMHO) remains the best solution for ad hoc filtering. @MariusMatutiae's note of it being effectively dead applies solely to its development. I can't think of any procmail bugs that I've ever experienced, and I've done ridiculous things like implement full-blown mailing lists in it. Maybe it hasn't received further development because the only direction to take it would be beyond its scope (e.g. anti-spam, better served by SpamAssassin or e.g. milter-greylist). – Adam Katz Jan 17 '15 at 22:37
  • And you are saying this to me because....? – MariusMatutiae Jan 18 '15 at 7:01

In case if link goes down, here's summary.

First, go to master.cf and register your script "myhook" by adding the following line:

myhook unix - n n - - pipe flags=F user=www-data argv=/path/to/script.sh ${sender} ${size} ${recipient}

Also, edit smtp line to tell Postfix to run the filter for any mail arriving via the SMTP delivery:

smtp inet n - - - - smtpd -o content_filter=myhook:dummy

Please note that if you are sending mails using the "sendmail" command, the filter will not trigger. In this case, add the option after the "pickup" delivery method:

pickup fifo n - - 60 1 pickup -o content_filter=myhook:dummy

Restart postfix: postfix reload

Make your script readable and executable by anybody: chmod +rx script.sh

Note that script is always triggered for any mail arriving. To specify exact address see @MariusMatutiae answer.

  • that got me "unknown mail transport error" ... – user1133275 Oct 4 '17 at 1:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.