Monitoring the use of php mail() function

In a busy webserver hosting multiple sites it can be quite useful to monitor and control which sites are using the php mail() function to send out emails. The simplest way to do that is to create a simple wrapper for /usr/sbin/sendmail

Create a wrapper named /usr/sbin/sendmail-wrapper as

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

and make certain it has the correct permissions to be executed
chown root:root /usr/sbin/sendmail-wrapper
chmod 755 /usr/sbin/sendmail-wrapper

Then edit /etc/php.ini and change
sendmail_path = /usr/sbin/sendmail-wrapper

If you are running PHP as CGI script there is little left to do. But since most modern webservers run php as either and Apache module or fast-cgi you need to set PHP variables to the shell environment. Easiest way to do this is to prepend a small php script through php.ini.
Create a simple files in /var/www/common/set_wrapper_envs.php

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

and edit /etc/php.ini and add
auto_prepend_file = /var/www/common/set_wrapper_envs.php
 

The above script will log everything to the default maillog as defined in /etc/rsyslog.conf. But since mail logs tend to be quite spammy it is better to create a rule to separate the logs.

So create a simple rule in /etc/rsyslog.d/00-sendmail-wrapper.conf

if $msg contains 'sendmail-wrapper' then /var/log/mail_wrapper.log


You can easily extend the wrapper to even control if a site or particular scripts are allowed to use the PHP mail() function using a couple of ifs. But if you need a more finely tuned control there is an excellent post by kargig in his blog of how to use policyd in similar situations.