Triggering a PHP script when your Postfix server receives a mail

In this tutorial, we will see how to trigger a PHP script each time your web server is receiving some e-mails.Why would you want to do that? Well you could want to do that to develop a custom mailing list system, to archive your mail in database, trigger commands in your website by sending mails... your imagination is the limit.

Getting started with a basic Postfix filter

Configuring Postfix

To trigger a PHP script, we are going to configure Postfix so that it delivers the mail to our script. First of all, you might want to have a global understanding of Postfix architecture. If you haven't read this article, read it now, it helps understand what's going on.

Now, let's add our filter. We do that in the master.cf file that contains the list of all processes run when a mail is delivered.

We have registered a script named "myhook".
Let's stay in master.cf. We must now tell Postfix when to run that script.

To do this, let's edit the smtp line and change it this way:

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

The -o content_filter=myhook:dummy tells Postfix to run the filter for any mail arriving via the SMTP delivery. Please note that is 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

Do not forget: after changing a configuration file, you must run the command:

postfix reload

Writing a basic filter

Now, let's write the script. Let's name it "postfix.php"
The first thing you want to do is make the script readable and executable by anybody (we can strengthen the rights later):

chmod +rx postfix.php

The script most be runnable from the command line, so it should start with: #!/usr/bin/php
(assuming your PHP CLI is in /usr/bin/php)

We will first write a script that does nothing, except writing a line in a temporary file at "/tmp/postfixtest".

This script does read the mail message that is sent over STDIN (the standard unix input).
It writes the output in our "/tmp/postfixtest" file. So now, you can see the content of the mail in the file.

What have we done so far?

So far, we have developed a system that triggers a script when a mail is received. The script prevents the mail from being normally delivered and instead, routes the content of the mail to another file (but we could make it analyse the mail and do various actions on it)

You see? The script is triggered. What this means is that our filter is always triggered, whatever the receiver is!

This might be useful in some case, but might be a bit of an overkill. Let's have a look at fine-tuning the Postfix configuration to trigger the script only for some recipients.

Tuning Postfix configuration

Running the script only for some mail adresses

To do this, we will need to write an "access" configuration file. In this configuration file, we can write down which mail address should be filtered;

Here is a sample "access" file.

david@example.com FILTER myhook:dummy

This file says that the mails to "david@example.com" should be delivered to our filter.
Postfix does not know how to read a simple "access" file. We must "hash" it so that postfix can read it:

postmap /etc/postfix/access

The postmap command should create a /etc/postfix/access.db file. It is a "hashed" version of the "access" configuration file that can be quickly read by Postfix.

Finally, we must reference the "access" file in the main.cf file.
Look for the smtpd_recipient_restrictions directive and add at the beginning of the directive:check_recipient_access hash:/etc/postfix/access

We can see a section with headers, and the content of the mail at the bottom. This is not very easy to analyse, and it will get even trickier if we have attachements. So parsing this by hand is not really a good idea. Instead, we might want to use one of the numerous PHP classes written to parse MIME content:

About the author

David is CTO and co-founder of TheCodingMachine. He is the co-editor of PSR-11, the standard that provides interoperability between dependency injection containers. David is the lead developer of Packanalyst, a website that references all PHP classes/interfaces ever stored on Packagist. He is also the lead developper of Mouf, the only graphical dependency injection framework and currently working on another PSR, regarding standardizing service providers (more containers goodness!).

At TheCodingMachine, we are using open-source tools daily to build our projects. And since we and our clients are ripping huge benefits from these open-source products, we also try to "give back" to the open-source community.

At TheCodingMachine, we are always looking for top freelance developers to work with us on our next state-of-the-art project.Interested in developing quality projects? We love good work and we pay fairly.