[ TL;DR, not a Postfix issue, rather a shell programming tutorial,
if you are not interested in one, feel free to move along. ]
On Sat, Jan 17, 2026 at 10:06:50AM +0100, Peter Uetrecht via Postfix-users
wrote:
> Certain recipients need to be rewritten if the sender is correct.
This is a typical application for a milter, but a pipe delivery
agent might do in a pinch.
> However, the Postfix pipe daemon never rewrites the recipient.
The pipe delivery agent does no rewrites, you're perhaps loosely trying
to refer to the program you've asked it run, which might be able to
"resubmit" the input message with a modified envelope.
> > rewritepipe unix - n n - - pipe
> > flags=Rq user=nobody argv=/usr/local/bin/rewrite-envelope.sh ${sender}
> > ${recipient}
Nothing usual ath the Postfix level.
> #!/bin/sh
>
> EX_TEMPFAIL=75
> EX_UNAVAILABLE=69
>
> SENDMAIL="/sbin/sendmail.postfix -G -i"
> TMPDIR="/var/spool/postfix/rewrite"
> TMPFILE="$TMPDIR/msg.$$"
I'd prefer to you use the "mktemp" command, which is largely immune to
the kind of issues you can run into by using "msg.$$".
> # Remaining arguments = recipients
> RECIPIENTS="$@"
Unlike "$@" which correctly retains the structure of the argument list,
this assignment does not if some of the elements contain whitepace.
> for ENVELOPE_TO in $RECIPIENTS
The robust syntax (and your shell variables don'g have to be in UPPER
CASE) is:
for rcpt in "$@"
> do
> NEW_TO="$ENVELOPE_TO"
> if echo "$ENVELOPE_FROM" | grep -qiP ".+@source\.dom$"
That's fragile, because the "echo" command interprects some special
characters in the input argument. A shell that has a "printf" built-in
is a better bet (in the form: printf -- "%s" "$arg"), or the argument
can be tested directly with shell-built-ins. For example, in bash:
$ for rcpt in {abc,def}@example.{com,commune}
do
if [[ "$from" = *@example.com ]]
then
printf -- "matchedd: %s\n" "$from"
else
printf -- "skipped: %s\n" "$from"
fi
done
Output:
matchedd: [email protected]
skipped: [email protected]
matchedd: [email protected]
skipped: [email protected]
> then
> if echo "$ENVELOPE_TO" | grep -qiP ".+@destination\.dom$"
> then
> NEW_TO="[email protected]"
> fi
With a similarly capable shell, you can combine both tests into one:
# Array syntax:
rcpts=()
for rcpt in "$@"
do
if [[ "$from" = *@example.com && "$rcpt" = *@example.net ]]
then
rcpts=("${rcpts[@]}" [email protected])
else
rcpts=("${rcpts[@]}" "$rcpt")
fi
done
> fi
> # echo "$SENDMAIL -f $ENVELOPE_FROM $NEW_TO < $TMPFILE || exit $EX_TEMPFAIL"
> $SENDMAIL -f "$ENVELOPE_FROM" "$NEW_TO" < "$TMPFILE" || exit $EX_TEMPFAIL
That looks like a single argument and also fails to protect against
leading "-" in the first recipient addresss. Instead:
exec sendmail -f "$sender" -- "$[rcpts[@]}" < $tmpfile
(The Postfix sendmail(1) command returns the appropriate exit code
automatically).
--
Viktor. 🇺🇦 Слава Україні!
_______________________________________________
Postfix-users mailing list -- [email protected]
To unsubscribe send an email to [email protected]