Simple PHP mail wrapper

If you run a webserver with several hundreds of virtual hosts running PHP, you definitely need to monitor or log the access to PHP’s mail() function. I describe in a short tutorial how to painlessly setup a simple sendmail wrapper to accomplish this.
This has been tested on a Debian Lenny 5.0 system running PHP 5.2.8 and Postfix.


Create a wrapper script in e.g. /usr/sbin/sendmail-wrapper-php:

#!/bin/sh
logger -p mail.info sendmail-wrapper-php: site=${HTTP_HOST}, 
 client=${REMOTE_ADDR}, script=${SCRIPT_NAME}, 
 pwd=${PWD}, uid=${UID}, user=$(whoami)
/usr/sbin/sendmail -t -i $*

Make sure it has correct access permissions:

chown root /usr/sbin/sendmail-wrapper-php
chmod 755 /usr/sbin/sendmail-wrapper-php

This script logs to syslog, usually configured to log mail.info to /var/log/mail.log.
We force all customers to use this wrapper script instead of the original /usr/sbin/sendmail binary. Modify your php.ini and add/change:

sendmail_path = /usr/sbin/sendmail-wrapper-php
auto_prepend_file = /var/www/common/php_set_envs.php

The auto_prepend_file directive is not necessarily needed if you run PHP in CGI-mode – the variables to be logged by the wrapper script are correctly set. For local PHP execution on the system and if you run PHP as Apache-module (apxs2), you better add this directive. The php_set_envs.php simply sets some PHP variables to the shell environment:

<?php
putenv("HTTP_HOST=".@$_SERVER["HTTP_HOST"]);
putenv("SCRIPT_NAME=".@$_SERVER["SCRIPT_NAME"]);
putenv("SCRIPT_FILENAME=".@$_SERVER["SCRIPT_FILENAME"]);
putenv("DOCUMENT_ROOT=".@$_SERVER["DOCUMENT_ROOT"]);
putenv("REMOTE_ADDR=".@$_SERVER["REMOTE_ADDR"]);

As you noticed, I put some more variables in this script. You could extend the sendmail wrapper script by $SCRIPT_FILENAME and $DOCUMENT_ROOT to make 100% sure you can find the right origin where mail() was initiated.

We’re all set now. Monitor your mail log by e.g.:

# grep sendmail-wrapper-php /var/log/mail.log
Dec 29 20:41:35 web logger: sendmail-wrapper-php: site=www.iezzi.ch, client=212.35.7.99, script=/test.php, pwd=/var/www/webXX/includes/wordpress, uid=4002, user=web2
Dec 29 20:42:52 web logger: sendmail-wrapper-php: site=webmail.onlime.ch, client=212.35.7.99, script=/index.php, pwd=/var/www/webYY/includes/roundcube, uid=4001, user=web1

12 Comments so far »

  1. Iezzi.ch Blog » Extensive sendmail wrapper with sender throttling said

    am January 3 2009 @ 3:43 pm

    [...] under their own UID. The wrapper described here is not just a PHP-only wrapper (as described in my Simple PHP mail wrapper tutorial) – it directly replaces /usr/sbin/sendmail so we are able track all sent email of the [...]

  2. Mail Versand quantitativ beschr said

    am February 19 2009 @ 5:19 pm

    [...] Ich bin per Zufall auf folgende Links gestossen: Iezzi.ch Blog Simple PHP mail wrapper Iezzi.ch Blog Extensive sendmail wrapper with sender throttling Damit kann man

  3. Whitenoise » Blog Archive » Part 1: Limiting and rate throttling php mail() function said

    am May 3 2009 @ 7:27 pm

    [...] The first step can be achieved by reading this great article: Simple PHP mail wrapper [...]

  4. Grimm said

    am June 30 2009 @ 2:17 am

    Thank you, this article helped me to find vulnerable site in 100+ virtualhosts. It’s really simple and efficient solution to php mail() logging.

  5. J-P said

    am August 15 2009 @ 3:15 pm

    Thanks, this script is awesome! It saved me a serious amount of time.

  6. Prasanna said

    am September 2 2009 @ 12:19 am

    How can we log the e-mail headers? i.e the to, from, reply-to addresses and any other additional headers being used in the mail() calls.

  7. John Campbell said

    am September 15 2009 @ 8:45 pm

    Thanks for this. I’m having a problem getting it to log anything more than “site=www.myexample.com”, however. Any idea why this could be? Thanks!

  8. Alexis said

    am September 24 2009 @ 4:48 pm

    Hello,

    Thanks for this script. I did it one like this too few years ago which included a limitation of the number of messages that could be sent with mail(). However it was not very functionnal. Additionnaly it logged the mails as well, but only with $PWD as I didn’t know auto_prepend_file command.

    Btw, I’ve got a problem with auto_prepend_file with website with safe mode activated. As the php_set_envs.php is owned by root it can’t be inserted in a page owned by another user. And I can’t change the owner of php_set_envs.php as it is included in all webpages of all our websites, with different UID.

    I don’t really understand why auto_prepend_file is included in the safe_mode check. It should just include it as it has been defined in the configuration file.

    Though, would one know if there is another solution than deactivating the safe mode for everybody ?

    Thanks in advance,
    regards

  9. Pratico fabrice said

    am September 28 2009 @ 4:20 pm

    Very nice, thank you ;)

  10. Prasanna said

    am November 16 2009 @ 12:33 pm

    I just added this to one of my sites and the log shows the following:

    [root@www log]# grep sendmail-wrapper /var/log/maillog
    Nov 16 06:24:27 www logger: sendmail-wrapper-php: site=www.mysite.com,

    Doesn’t show any other details like script name etc.
    What could be wrong?

  11. Prasanna said

    am November 16 2009 @ 1:02 pm

    Also, I see an error of this kind:

    Nov 16 06:49:31 www postfix[4111]: fatal: /etc/postfix/main.cf, line 640: missing ‘=’ after attribute name: “/usr/sbin/sendmail-wrapper-php”

  12. PHP-Mail-Funktion begrenzen - Server Support Forum said

    am April 24 2011 @ 7:42 am

    [...] [...]

Comment RSS · TrackBack URI

Leave a comment

Name: (Required)

eMail: (Required)

Website:

Comment: