Sendmail Wrapper
We had some spam problems last week, one of them caused by a form that wasn’t properly escaped. While that problem was fixed, the real problem was that it was hard to figure out what script had the issue.
To solve this, I wrote a sendmail wrapper for use by PHP (though really it could be used by anything) that logs the message along with the date, a message id (also inserted in th e headers) and the current directory (which gives the location of the original script).
It also extracts out the domain name from the current directory, but this is server specific so you’ll need to change the pattern to match your file system.
Eventually I’d like to include support to check for a maximum number of recipients, and maybe some other heuristics to check for spam.
You can get the script at:
http://gregmaclellan.com/php/sendmail.phps
You should save this file as /usr/local/sbin/sendmail_logged.
The reporting script is at:
http://gregmaclellan.com/php/mailreporting.sh
There are instructions in this file for how to add it to cron.
Let me know if you have any comments, suggestions, do any improvements, or find any bugs.

January 20th, 2006 15:49
Hey,
Are you using CGI-PHP? I ask because I’m using mod_php and I don’t get the same stuff in the environment passed to my mail script.
I used a little different approach to accoumplish a similar effect:
I have an auto-prepended script set in my php.ini with stuff like:
putenv(’HTTP_HOST=’. $_SERVER['HTTP_HOST']);
putenv(’SCRIPT_NAME=’ . $_SERVER['SCRIPT_NAME']);
putenv(’REMOTE_ADDR=’ . $_SERVER['REMOTE_ADDR']);
That kicks some useful info down to the sendmail wrapper environment. Apache senenv directives don’t make it through for me, unfortunately.
Then I went low-tech with my wrapper script:
#!/bin/sh
logger -p mail.info vhostmail: site=${HTTP_HOST}, client=${REMOTE_ADDR}, script=${SCRIPT_NAME}
/usr/sbin/sendmail -t -i $*
Trying this on my production box now.
January 23rd, 2006 12:22
This is using CLI-PHP (as opposed to CGI). The difference is in the environment variables that get passed, and the output of error messages (text vs html).
I wanted to avoid using auto-prepend, espessially since a user could change thoses values if they wanted to. Putting the information into syslog is a good idea though.
March 9th, 2006 07:53
Hi,
I have a server with host some web page using php.
Some day ago this server is used for spam by php mail function in some email form.
I used your script with some hoppes to identifier that script, but the log that generated show me SCRIPT_NAME = the name of your script (sendmail_logger) and don’t the script used in form to send the mail…..
Do you know how can I log or make a way to find it?
Tkz for your attention,
Joao Pedro
March 9th, 2006 21:04
There’s really not an easy way to get the actual executing script’s name, because it’s not something that’s normally passed to sendmail. You can try the method Harold Paulson uses above. For the most part, getting the working directory (`pwd`) should usually be enough to figure out what script it is, unless you have hundreds of scripts that send mail all in the same directory.
January 17th, 2007 12:33
[...] I’ve posted my php sendmail wrapper before, but I just noticed that Ilia Alshanetsky has written a php mail logging patch that essentially does the same thing, but from within PHP itself. This is nice because it can log the full path of the file and line where mail() was called, whereas my script can only log as much info as PHP passes to sendmail (which isn’t very much) and what it can get from the environment. The downside is since it’s a patch, it requires recompiling - my script can be dropped into any installation (PHP4/5, and maybe even 3) and just requires a simple php.ini change. I should also point out that if you’re using this, you should be sure that you don’t “whitelist” localhost in your mail server, or otherwise people can just connect to your SMTP server locally, and send mail without requiring a username or password. If they use SMTP you can’t see what script or virtual host sent the mail either way, but at least if you require authentication you can see what account is being used if it becomes an issue. [...]
March 7th, 2007 01:52
Has anyone other than me notice a long delay when using ths wrapper ?
It seems as everything works as expected, but the php scripts takes more than 30 seconds before it returns the output to the browser when executing the mail command.
It hangs when its doing the popen to the sendmail.
March 7th, 2007 02:03
To be more precise, it is exactly when doing the pclose() at the end that it takes a while to return.
April 13th, 2007 06:08
Hi all,
I’ve made this change to the script:
19a20,26
> if($argc > 1)
> {
> for($i = 1; $i {
> $sendmail .= ” ” . $argv[$i];
> }
> }
This allows it to preserve command line arguments passed with the mail() function (like “-f sender”).
April 13th, 2007 06:11
Sorry, the right code is:
19a20,26
> if($argc > 1)
> {
> for($i = 1; $i {
> $sendmail .= " " . $argv[$i];
> }
> }
April 13th, 2007 06:13
Sorry again. ;)
19a20,26
> if($argc > 1)
> {
> for($i = 1; $i < $argc; $i++)
> {
> $sendmail .= ” ” . $argv[$i];
> }
> }
April 20th, 2007 17:06
My installation (PHP4, FC3) delays form processing confirmation, but doesn’t log to the folder /var/log/phpmail
Any ideas?
April 20th, 2007 18:17
Cool script. I have trouble running it under Suse 10.1 (PHP5) Maybe its the safemode=on. I will investigate…
Two lines drop warnings; $ENV["PWD"] and $data are not initialized.(line 25 and 35 or so)
April 21st, 2007 04:36
Also - every time I submit a form, I get 500Mb in my error log. I’ve tried with register_globals =On and Off
April 23rd, 2007 09:35
I have trouble running this script; maybe because phpinfo() shows php is compiled with –disable-cli
Is there a useful alternative using Perl?
I found a simple shellscript that (should) drop number of params and all parameters given to a logfile and pipe to sendmail:
#!/bin/sh
logfile=/var/log/wrapperlog
(date; echo ” | $# | $@”) >> $logfile
exec /usr/lib/sendmail “$@”
April 23rd, 2007 10:16
update - with $PWD
#!/bin/sh
logfile=/var/log/wrapperlog
(date; echo ” | $# | $PWD | $@”) >> $logfile
exec /usr/lib/sendmail “$@”
April 25th, 2007 16:30
I’ve attempted to use various wrapper scripts to help with tracking down spam, but have found most too slow or cpu intensive to implement in busy environments.
Does any one have performance notes on this wrapper?
What I would like to see is a way to override the mail function in PHP and auto-include some additional headers. On many shared hosting environments, such as Plesk, Ensim or cPanel based systems, you can add some settings within apache on a per site basis. Perhaps some way to use php admin flags or apache’s own environment variables could be useful.
For example, if I were to set an apache env variable to have the site’s admin user name could this be logged or otherwise inserted into the email using your script?