sendmail-wrapper for PHP

Years ago I wrote about the extensive sendmail wrapper with sender throttling, a pretty simple Perl script. It reliably provided throttling of the email volume per day by the sender’s original UID (user id). It also logged the pathes of scripts that sent emails directly via sendmail (e.g. via PHP’s mail() function). The main flaw in the original sendmail wrapper was security, though. As in Linux, every executable script must be readable by the user that calls it, the throttle table in MySQL was basically open and every customer could manipulate it. Every customer could raise his own throttling limit and circumvent it.

Today, I’m publishing my new sendmail-wrapper that is going to fix all the flaws of the previous version and add some nice extras.
The new sendmail-wrapper is written entirely in PHP and does not require any external libraries. It is a complete rewrite and has pretty much nothing in common with the old Perl version.

This project is hosted on Github


  • Lets you monitor any mail traffic from PHP scripts
  • Allows throttling (limiting) emails sent by PHP’s mail() function
  • Throttle by sent email and/or recipient count per day
  • Logs both to syslog and database with message metadata
  • Logs common mail headers like From, To, Cc, Bcc, Subject
  • Fixes Return-Path header on the fly for users who did not correctly set it
  • Highly secured setup, customers cannot access the logging/throttling database
  • Standalone PHP application without any external library dependencies
  • Built for shared webhosting environment where PHP runs as cgi/FastCGI/suPHP
  • No cronjobs required, sendmail-wrapper will reset counters automatically every day

The idea behind this secure setup:

Logging is done only via syslog, no customer can read or modify syslog entries. The sendmail-wrapper is split into two components: sendmail-wrapper.php and sendmail-throttle.php. The wrapper component will only do some syslogging and analyze some headers. It will also fix the Return-Path header if applicable as most customers forget to correctly set it in PHP. sendmail-wrapper.php is readable and executable by every customer. This is a strong requirement as our customers all run their script under their own UID, PHP runs as cgi/FastCGI/suPHP. The throttle component is where it gets more interesting. The sendmail-throttle.php script can only be executed by user sendmailwrapper which is an equally unprivileged system user like every other customer user. The throttling script will NOT be world readable and it will read it’s configuration from an extra file config.private.ini which contains the database password. The correct permissions are set by our installation script.

Return-Path fixing

Most customers just forget to set a Return-Path when they use PHP’s built-in mail() function. Even if they try to set it in the $additional_headers variable, it will not get correctly set on most systems. The only way ist to set it via the $additional_parameters variable, using the -f or -r switches. 99% of our customers simply can’t manage this, seriously!
This sendmail-wrapper is extracting the email address from the Return-Path header, and if it doesn’t exist, it will just take the sender’s address (from the From header) as return-path. This is actually one of the most important features of my sendmail-wrapper, even if it might get overlooked and you’re installing the wrapper because of it’s logging and throttling capabilities.


(for detailed instructions, please consult the README on Github)

Clone repository from GitHub:

Setup system user for sendmail-wrapper:

The installer script will correctly setup permissions and symlink the wrapper scripts:

Add the following lines to your /etc/sudoers:

Add/modify the following in your php.ini:

Import the sendmailwrapper database schema:

Create a MySQL user with the following permissions:


Default configuration can be found in config.ini:

You should not change any of the above values. Create your own config.local.ini instead to overwrite some values, e.g.:

Never put your database password in any of the above configuration files. Use another configuration file called config.private.ini instead, e.g.:

Sample syslog output

MySQL database ’sendmailwrapper›

You may access both MySQL tables directly: throttle to tweak each system user’s limits (they will be persistent! Only counters are gettingn reset every day), messages for detailed message header reviewing or for statistical purposes.

Leave a Comment