> I've set it (correctly I think) on our server, to collect
> email addresses for a company newsletter. I've downloaded
> the manual and read it over and over, but when I send
> X-Commands and try to distribute a newsletter, absolutely
> nothing happens.
>
> I've spent hours trying to figure out what it is I'm doing
> wrong [...]
One thing to check for: The X-Command has to be in the _header_ of
e-mail message sent to list-request(a)domain.com. Some mail clients
won't let you add your own custom header lines, or they make it
difficult.
I modified the way X-Command works, to support list admin commands
in the _body_ of the message. The logic checks to see if the from
address matches the list maintainer address, and if it does,
it allows the list commands. I didn't add a password check, but
that would have been straightforward as well. The list maintainer
check can be easily generalized to allow more than one maintainer.
The mod is in rc.request, just ahead of the recipe that already
handles X-Command. Here's the logic:
#
# Or is it a special remote "admin" command from the maintainer?
#
:0 H wf:dist.lock
* $^From:.*$maintainer
* ^Subject:.*admin
* $!^X-Loop: $listaddr
* $!^X-Loop-Admin: $listaddr
| do_admin
which is inserted just ahead of this part of the recipe:
#
# Or is it a remote X-Command from our maintainer?
#
:0 H wf:dist.lock
* $^$X_COMMAND:.*$maintainer[ ]*$X_COMMAND_PASSWORD
* $!^X-Loop: $listaddr
| x_command
The extra logic looking for X-Loop-Admin checks for the cases where
mail to the maintainer is looping. This can happen sometimes, and
when it does, bad things happen.
The "do_admin" script is in in the .bin directory, and is a slight
variation on "x_command":
#! /bin/sh
:
echo=echo # /bin/echo
test=test # /bin/test
cat=cat # /bin/cat
rm=rm # /bin/rm
formail=formail # /usr/local/bin/formail
subscribe=subscribe # ../.bin/subscribe
unsubscribe=unsubscribe # ../.bin/unsubscribe
multigram=multigram # ../.bin/multigram
tmprequest=tmp.request
tmpfrom=tmp.from
dist=dist
log=log
$test -z "$listaddr" &&
$echo "Don't start this script directly, it is used in rc.request" && exit 64
X_ENVELOPE_TO=$list-request # to convince (un)subscribe we used the right
export X_ENVELOPE_TO # address
$cat >$tmprequest
$formail -a X-Processed: <$tmprequest
set dummy `egrep '^(subscribe|unsubscribe|checkdist|showdist|showlog|help|info|wipelog|version)' < $tmprequest`
shift
while $test $# != 0
do
case "_$1" in
_subscribe|_unsubscribe|_checkdist)
if $test $# = 1
then
$echo "X-Diagnostic: Missing argument for $1"
set help
fi;;
esac
case "_$1" in
_subscribe)
$echo "From $2 " >$tmprequest
$echo "From: request ($listreq)" >>$tmprequest
$echo "Reply-To: $2" >>$tmprequest
$echo "To: $listreq" >>$tmprequest
$echo "Subject: subscribe $2" >>$tmprequest
$echo "$2" >$tmpfrom
$test -z "$subscribe_log" ||
$echo "x_command: subscribe" >>$subscribe_log
$subscribe <$tmprequest ||
$echo "X-Diagnostic: Unscreened, not subscribed"
shift ;;
_unsubscribe)
$echo "From $2 " >$tmprequest
$echo "From: $listreq" >>$tmprequest
$echo "Reply-To: $2" >>$tmprequest
$echo "To: $listreq" >>$tmprequest
$echo "Subject: unsubscribe $2" >>$tmprequest
$echo "$maintainer" "$2" >$tmpfrom
$test -z "$subscribe_log" ||
$echo "x_command: unsubscribe" >>$subscribe_log
$unsubscribe <$tmprequest | $SENDMAIL $sendmailOPT `cat $tmpfrom`
shift ;;
_checkdist)
$echo "Multigram checking the dist file for matches with"
$echo "$2:"
$echo ""
$echo "From $2" | $multigram -b8 -l-32767 dist
$echo ""
shift ;;
_showdist)
$echo "--- Current subscribers:"
$cat $dist
$echo "--- End of subscriber list" ;;
_showlog)
$echo "--- Current log:"
$cat $log
$echo "--- End of log" ;;
_wipelog)
$cat /dev/null >$log ;;
_version)
flist -v 2>&1
echo ""
procmail -v 2>&1 ;;
_help|_info)
$echo "Known $X_COMMAND keywords:"
$echo " subscribe mailaddress"
$echo " unsubscribe mailaddress"
$echo " checkdist mailaddress"
$echo " showdist"
$echo " showlog"
$echo " wipelog"
$echo " version"
$echo " help"
$echo " info" ;;
*) $echo "X-Diagnostic: Unknown command $1" ; set dummy help ;;
esac
shift
done
The key differences between "do_admin" and and "x_commend" are below.
The lines with exclamation points,
$cat >$tmprequest
! $formail -R$X_COMMAND: X-Processed: <$tmprequest
! set dummy `$formail -x$X_COMMAND: <$tmprequest`
! shift; shift
! test "_$X_COMMAND_PASSWORD" = "_$1" && shift
while $test $# != 0
do
case "_$1" in
are replaced with these:
$cat >$tmprequest
! $formail -a X-Processed: <$tmprequest
! set dummy `egrep '^(subscribe|unsubscribe|checkdist|showdist|showlog|help|info
|wipelog|version)' < $tmprequest`
! shift
Basically, instead of looking for X-Commmand in the header, and then
extracting the commands from those lines, the script looks for the
commands as the appearing in the first column, and then works through
those commands one-at-time as the previous script did. The password
handling was removed, but with a little work could be added back in.
For now, the check for the maintainer address is considered to
be sufficient, though this could be spoofed, and something more
robust is desirable for production use. The advantage of allowing
the commands in the body of the message is that the user who is
managing the list can use any mail client, and doesn't need to
figure out how to create custom header lines.
Here's an example of an admin message processed by the method
described above:
From: list_manager(a)domain.com
To: list-request(a)list_domain.com
Subject: admin
unsubscribe old_user_address(a)old.com
subscribe new_user_addr(a)new.com
showdist