Tracking your emails with slightly evil Exim filters and Apache.


Why this is a terrible idea/problems/limitations:

There are a few reasons not to do this. The ones that immediately spring to mind are, it’s slightly evil and an invasion of privacy; It isn’t particularly scalable; Tampering with emails in transit isn’t a good idea and things can go wrong. While the filter runs as a reduced priv process it could be a security issue.

In addition to this it isn’t very accurate. It will only tell you if an email has been rendered, not read, and there are a number of circumstances that this could occur. Linking to images in this manner could increase your spam rating. It requires a html email client and for image loading to be enabled which may not always be the case. There is no way to accurately determine who is behind the keyboard. You may be creating evidence you don’t want to have. Forwarded/replied to messages may create incorrect results.

None of the code provided is particularly well audited or robust. Use at your own risk etc.

I’m only classing this as slightly evil as all we are grabbing is the UA string, IP and date read. With some JS work we could get rather a lot more. Also this isn’t a new concept and is reasonably widely used, plus there are limits to the amount of evil you can accomplish in about 6 hours.

To reiterate; these are rough scripts as a proof of concept and have not been reviewed.


We have an email sent by an email client, this email passes through a server and is delivered to another server where a client can read it. In our scenario the first client sends the email with and embedded link to an image as part of their signature, the server receives that email and searches for that link, rewriting it to include a unique id. Also information to/from/subject/date are saved locally in a database with that unique ID. When delivered to the end client the rendering of the email causes that link to activate at which point we know the mail has been rendered. We then save information such as date/IP/User Agent to the database connected with that email sent.

After that the database can be queried for emails sent and information about hits on them.

What you need:

An image to embed in your signature.

The Scripts:

filter.php ; this is the filter exim4 will apply to emails
return.php ; this is the “image” we will link to
details.php ; this is a simple demo of getting info out of the database
list.php ; a simple list of all emails tagged
sql.txt ; the sql to create the database

The configuration:

Step 1) Exim4
First we need to find the remote_smtp transport in exim4 (on Debian with a split config this is located in /etc/exim4/conf.d/transport/30_exim4-config_remote_smtp ). Amend this config to:

debug_print = “T: remote_smtp for $local_part@$domain”
driver = smtp
transport_filter = /etc/exim4/filter.php $host $host_address $sender_address $pipe_addresses

Likely your config will look slightly different however the red portion is what is important. Save filter.php to /etc/exim4 and make it executable. Edit filter.php to update your MySQL details.

Step 2) Apache2
Save return.php to a web accessible directory; edit it and update the MySQL connection details. You will also need to update the link to your actual signature image in this file. Open up the apache virtual host config for your server and add something like:

RewriteEngine on
RewriteRule ^/img/sig-([0-9]+).png$ /return.php

Obviously you should adapt this to fit your host/other requirements. The general gist is that filter.php rewrites the url in your signature and this rule makes sure what it rewrites it to is a valid file, one which when called will log information regarding that message.

You will also need to load details.php and list.php into a directory; preferably secured by a htaccess of some description. You will need to edit those to place the MySQL details into them.

Step 3) MySQL
Use your favorite method to import sql.txt into your database. Verify that you can login from the IP that your mail/web server will use to connect.

Step 4) Email Client
Update your email client to embed the unaltered image as your signature. This will be pattern matched by filter.php (the $STRREP variable) and should be located in the /img/ directory if you used the above apache2 rule. If you didn’t then you may need to edit the filter.php to point to the right place.

Step 5) Adjustments
You will need to adjust the scripts to your environment. No solid checking for how strings are choped up has been done yet. You may want to tweak the database etc.

Step 6) Profit
Visit the list.php file in your web directory and you should have a list of emails sent out with links to their details. When a recipient views a mail they should show up here.

The future:

It would be nice if the script could have some error checking and be a little more robust. I’d love to ajaxify the display pages to make them more usable. These instructions will get more professional etc. I’d like to edit the scripts to make certain all variables are declared and easily changeable, maybe an include file?

Comments (1) Trackbacks (0)
  1. Murray Collingwood
    10:08 am on August 22nd, 2018

    Unfortunately this doesn’t work with Gmail – Google caches the image and replaces the URL with one that points to their own cached version of the image.
    PRO: The email image continues to be visible even if the original site goes offline or the image is deleted.
    CON: Tracking views of the email won’t generate any tracking data.

Leave a comment

No trackbacks yet.