PHP Code:
#! /usr/local/bin/php
<?php
/*
* dhmailer.php - light weight mailing list script
*
* (c) 2009 Dommel Hosting / T. Bloo
*
* history:
* 2011-11-28 cleaned for publication, T
* 2011-11-17 improved address extraction, T
* 2011-11-12 added return path and failure logging, T
* 2011-11-11 added delay on error, T
* 2011-10-21 removed cc and bcc from resend, T
* 2011-10-12 sender format, T
* 2011-10-07 circular addresses, restricted allow, T
* 2011-10-06 improved realname handling, T
* 2011-09-30 changed realname handling, T
* 2011-09-28 sender visible, T
* 2011-09-27 use ini files, T
* 2011-09-23 standalone with .conf file, T
* 2011-09-20 working as part of userbase, T
* 2011-09-19 started from earlier work, T
*
* remark:
* this is a command line script, not a webserver program
*
* dependencies:
* php 5 engine on /usr/local/bin/php
*
* simplified usage:
* phpmailer.php listname
*
*/
### error handling
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
ini_set('html_errors', 0);
### defines
define('VERSION', 'DH-Mailer v1.4');
define('LOCATION', dirname(__FILE__));
define('TIMESTAMP', date('Y-m-d H:i:s'));
define('LOGFILE', LOCATION.'/dhmailer.log');
define('NL', "\n");
define('CRLF', "\r\n");
define('TAB', "\t");
### command line arguments
@list($scriptname, $listname) = $argv;
define('TESTSCRIPT', strpos($scriptname, '_test') !== false);
if ($listname == '')
{
echo 'error: listname empty'.NL;
file_put_contents(LOGFILE, TIMESTAMP.TAB.'empty listname'.NL, FILE_APPEND);
exit(1);
}
### get configuration
$config = dhmailer_readconfig($listname);
dhmailer_logfile($config, 'message', $listname);
### get and parse mail message
$messagetext = dhmailer_readmessage();
if (TESTSCRIPT) file_put_contents(LOGFILE, TIMESTAMP.TAB.'messagein'.TAB.$messagetext.NL, FILE_APPEND);
$message = dhmailer_parsemessage($messagetext);
dhmailer_logfile($config, 'subject', $message->subject);
dhmailer_logfile($config, 'sender', $message->sender);
### handle restricted lists
if ($config->restricted)
{
if (!in_array($message->from, $config->addresses) and !in_array($message->from, $config->restricted_allow))
{
# restricted_text = 'error: address @@@ is not allowed to send messages to this list'
$text = str_replace('@@@', $message->from, $config->restricted_text);
dhmailer_logfile($config, 'restricted', $message->from);
sleep(300);
dhmailer_sendemail($message->from, $message->subject, $text, $config->listaddress, $config->listaddress, '', $config->errorsaddress, $message->from);
exit(0);
}
}
### handle large messages
if ($config->maxlength > 0)
{
$length = strlen($messagetext);
if ($length > $config->maxlength * 1024)
{
# maxlength_text = 'error: message length of $$$ is too large for this list'
$text = str_replace('$$$', $length, $config->maxlength_text);
dhmailer_logfile($config, 'maxlength', $length);
sleep(60);
dhmailer_sendemail($message->from, $message->subject, $text, $config->listaddress, $config->listaddress, '', $config->errorsaddress, $message->from);
exit(0);
}
}
### append subject tag
if ($config->subjecttag)
{
if (stripos($message->subject, @$config->subjecttag_text) === false)
{
$message->subject = $config->subjecttag_text.' '.$message->subject;
}
}
### append footer message
if ($config->addfooter)
{
$message->body[] = $config->addfooter_text;
}
### reply to list or original address
if ($config->replytolist)
{
$realname = dhmailer_realname($message->sender);
if ($realname == '')
{
$message->sender = '"'.$config->listaddress.'" <'.$config->listaddress.'>';
}
else
{
# senderformat = '"_REALNAME_ @ _LISTNAME_" <_LISTADDRESS_>'
$sender = $config->senderformat;
$sender = str_replace('_REALNAME_', $realname, $sender);
$sender = str_replace('_LISTNAME_', $config->listname, $sender);
$sender = str_replace('_LISTADDRESS_', $config->listaddress, $sender);
$message->sender = $sender;
}
$message->replyto = $config->listaddress;
}
else
{
$message->replyto = $message->from;
}
dhmailer_logfile($config, 'sender', $message->sender);
### append mailer program signature
$message->headers[] = 'X-Mailer: '.VERSION;
### send emails
foreach ($config->addresses as $address)
{
dhmailer_sendemail($address, $message->subject, implode(CRLF, $message->body), $message->sender, $config->errorsaddress, '', '', $message->replyto, $message->headers);
dhmailer_logfile($config, 'send', $address);
}
### ready and success
exit(0);
### read and parse config file
function dhmailer_readconfig($listname)
{
# read ini file
$file = LOCATION.'/'.$listname.'.ini';
$inis = @parse_ini_file($file);
# report error
if ($inis === false)
{
echo 'error: ini file error'.NL;
file_put_contents(LOGFILE, TIMESTAMP.TAB.'inifile error'.TAB.$listname.NL, FILE_APPEND);
exit(1);
}
# convert to object
$config->listname = trim(strtolower(@$inis['listname']));
$config->domain = trim(strtolower(@$inis['domain']));
$config->listaddress = $config->listname.'@'.$config->domain;
$config->logfile = trim(@$inis['logfile']);
$config->senderformat = trim(@$inis['senderformat']);
if ($config->senderformat == '')
{
$config->senderformat = '"_REALNAME_ @ _LISTNAME_" <_LISTADDRESS_>';
}
$config->errorsaddress = trim(strtolower(@$inis['errorsaddress']));
if ($config->errorsaddress == $config->listaddress)
{
file_put_contents(LOGFILE, TIMESTAMP.TAB.'circular'.TAB.$config->errorsaddress.NL, FILE_APPEND);
$config->errorsaddress = '';
}
$config->replytolist = intval(@$inis['replytolist']);
$config->subjecttag = intval(@$inis['subjecttag']);
$config->subjecttag_text = @$inis['subjecttag_text'];
if ($config->subjecttag_text == '')
{
$config->subjecttag_text = '['.$config->listname.']';
}
$config->restricted = intval(@$inis['restricted']);
$config->restricted_text = @$inis['restricted_text'];
if ($config->restricted_text == '')
{
$config->restricted_text = 'error: address @@@ is not allowed to send messages to this list';
}
$config->restricted_allow = array();
$addresses = explode(',', @$inis['restricted_allow']);
foreach ($addresses as $address)
{
$address = strtolower(trim($address));
if ($address != '')
{
$config->restricted_allow[] = $address;
}
}
$config->maxlength = intval(@$inis['maxlength']);
$config->maxlength_text = @$inis['maxlength_text'];
if ($config->maxlength_text == '')
{
$config->maxlength_text = 'error: message length of $$$ is too large for this list';
}
$config->addfooter = intval(@$inis['addfooter']);
$config->addfooter_text = @$inis['addfooter_text'];
$config->addresses = array();
foreach (@$inis['addresses'] as $address)
{
$address = strtolower(trim($address));
if ($address == $config->listaddress)
{
file_put_contents(LOGFILE, TIMESTAMP.TAB.'circular'.TAB.$address.NL, FILE_APPEND);
}
else
{
$config->addresses[] = $address;
}
}
# return configuration
return $config;
}
### write to list log file if enabled
function dhmailer_logfile($config, $message, $argument)
{
if ($config->logfile != '')
{
chdir(LOCATION);
$ok = file_put_contents($config->logfile, TIMESTAMP.TAB.$message.TAB.$argument.NL, FILE_APPEND);
if ($ok === false)
{
$ok = file_put_contents(LOGFILE, TIMESTAMP.TAB.'logfile problem'.TAB.$config->logfile.NL, FILE_APPEND);
}
}
}
### send email with headers
function dhmailer_sendemail($to, $subject, $message, $from, $sender, $cc = '', $bcc = '', $replyto = '', $extraheaders = array())
{
$to = trim($to);
$from = trim($from);
$cc = trim($cc);
$bcc = trim($bcc);
$replyto = trim($replyto);
$sender = trim($sender);
$subject = trim($subject);
$headers = '';
if ($from != '') $headers .= 'From: '.$from.CRLF;
if ($cc != '') $headers .= 'Cc: '.$cc.CRLF;
if ($bcc != '') $headers .= 'Bcc: '.$bcc.CRLF;
if ($replyto != '') $headers .= 'Reply-To: '.$replyto.CRLF;
foreach($extraheaders as $extra)
{
if ($extra != '') $headers .= rtrim($extra).CRLF;
}
$success = false;
if (strpos($to, '@') !== false)
{
$success = mail($to, $subject, $message, $headers, '-f'.$sender);
}
if (!$success or TESTSCRIPT)
{
file_put_contents(LOGFILE, TIMESTAMP.TAB.'sendemail'.TAB.'s:'.intval($success).'|t:'.$to.'|s:'.$subject.'|f:'.$from.'|s:'.$sender.'|c:'.$cc.'|b:'.$bcc.'|r:'.$replyto.'|h:'.$headers.'|e:'.implode(NL, $extraheaders).'|m:'.$message.NL, FILE_APPEND);
}
return $success;
}
### get data from standard input
function dhmailer_readmessage()
{
$fd = fopen('php://stdin', 'r');
$text = '';
while (!feof($fd))
{
$text .= fread($fd, 1024);
}
fclose($fd);
return $text;
}
### parse email headers and body
function dhmailer_parsemessage($mailmessage)
{
$message->headers = array();
$message->body = array();
$message->to = '';
$message->from = '';
$message->subject = '';
# split into lines
$lines = explode(NL, $mailmessage);
# parse special from line at start
$firstline = array_shift($lines);
@list($label, $address, $rest) = explode(' ', $firstline);
$message->from = dhmailer_cleanaddress($address);
# collect header and body lines
$body = false;
foreach ($lines as $line)
{
$line = rtrim($line);
if (!$body and $line == '')
{
$body = true;
}
else
{
if ($body)
{
$message->body[] = $line;
}
else
{
$parts = explode(':', $line);
$name = strtolower(trim(array_shift($parts)));
$argument = trim(implode(':', $parts));
switch ($name)
{
case 'to' :
$message->to = dhmailer_cleanaddress($argument);
break;
case 'from' :
$message->sender = $argument;
if ($message->from == '')
{
$message->from = dhmailer_cleanaddress($argument);
}
break;
case 'cc' :
$message->cc = $argument;
break;
case 'bcc' :
$message->bcc = $argument;
break;
case 'reply-to' :
$message->replyto = $argument;
break;
case 'return-path' :
$message->returnpath = $argument;
break;
case 'subject' :
$message->subject = $argument;
break;
default :
$message->headers[] = $line;
break;
}
}
}
}
# remove additional empty last lines
if (end($message->body) == '') array_pop($message->body);
if (end($message->body) == '') array_pop($message->body);
# return result
return $message;
}
### remove real names from address line
function dhmailer_cleanaddress($address)
{
$address = strtolower(trim($address));
$address = str_replace('<', '', $address);
$address = str_replace('>', '', $address);
$parts = explode(' ', $address);
$address = array_pop($parts);
return $address;
}
### get real names from address line
function dhmailer_realname($sender)
{
# remove unwanted characters
$sender = trim($sender);
$sender = str_replace('<', '', $sender);
$sender = str_replace('>', '', $sender);
# test for multiple parts
$parts = explode(' ', $sender);
if (count($parts) <= 1)
{
# only plain email address
$name = $sender;
}
else
{
# realname <user@domain>
array_pop($parts);
$name = implode(' ', $parts);
$name = str_replace('"', '', $name);
$name = trim($name);
}
# get user part of user@domain
@list($name, $domain) = explode('@', $name);
return $name;
}
?>
Exim restarten en testen. Misschien moet je in exim.conf nog de trusted_users instelling aanpassen.