RSS-Feed anzeigen

jahlives

autoreply mit Postfix

Bewerten
autoresponder mit postfix

Für dovecot-sieve gibt es mit vacation ein Plugin, welches Abwesenheitsmeldungen erstellt und verschickt. "Leider" ist vacation so geschrieben, dass maximal einmal pro Tag eine Mail pro Sender rausgeht. Will man also z.B. für eine info-Adresse jede Mail mit einer Meldung bestätigen, geht dies mit vacation nicht ohne den Quelltext zu verändern.

Es gibt jedoch bei Postfix eine "einfache" Möglichkeit Scripte in den Zustellprozess einzubauen

Voraussetzungen
  • Zugriff als root auf die Konsole (telnet oder ssh)
  • bash muss instaliert sein, weil der Code bash-spezifisch ist. Andere Shells dürften nicht gehen. Bash gibts bei ipkg
  • egrep muss installiert sein. Ist afaik nicht Bestandteil der Firmware, sollte es aber bei ipkg geben
  • bei den restlichen verwendeten Programme (z.B. awk) sollten die Versionen der Firmware eigentlich gehen
  • vor der Verwendung unbedingt die Konfigurationsvariabeln im Script für eure Umgebung anpassen!
Konfiguration von Postfix

virtual

In der Datei virtual legt man pro Adresse, die autoresponder haben sollen, einen Eintrag in der folgenden Form an
Code:
postmaster@domain.tld user@domain.tld,user@domain.tld@autoreply.domain.tld
Mails für postmaster@domain.tld werden hierbei an den user@domain.tld geschickt. Zusätzlich geht die Mail an die zweite Adresse, welche den autoresponder von postfix verarbeitet.

autoreply.domain.tld darf keinesfalls unter mydestination oder virtual_mailbox_domains in der main.cf aufgeführt sein!


Danach die Datei mittels postmap für postfix lesbar machen
Code:
postmap /path/to/virtual
transport
In der Datei transport wird auf Basis der Domain der Empfangsadresse der "Lieferweg" festgelegt. Hier drin legen wir einen Eintrag für die autoreply-Adresse an und weisen diesem einen Postfix-Handler zu (auch diese Datei muss mittels postmap kovertiert werden)
Code:
autoreply.domain.tld autoreply:
Wenn also eine Mail an die autoreply-Domain geschickt wird, dann wird der Postfix-Handler autoreply aufgerufen. Diesen müssen wir erst noch defnieren.

master.cf
In master.cf werden die "Dienste" von Postfix definiert und konfiguriert. Hier müssen wir für autoreply einen Handler erstellen. Dieser kann so ausschauen
Code:
autoreply    unix    -    n    n    -    -    pipe
 flags= user=nobody argv=/opt/etc/postfix/autoreply ${sender} ${mailbox}
Wichtig: Obiges müssen zwei Zeilen sein. Dabei darf man in der ersten Zeile nur und ausschliesslich TABs als "Leerzeichen" verwenden. Die zweite Zeile muss mit einem echten Leerzeichen beginnen und darf nur Leerzeichen als Whitespaces enthalten.

Wenn also autoreply aufgerufen wird, dann "piped" Postfix die Mail an das angegebene Script. Neben dem Inhalt der Mail via stdin übergibt Postfix 2 Parameter an das Script. Damit das Script weiss von wem die Mail ist und wohin die Meldung geschickt werden soll.

main.cf
Jetzt muss man nur noch in main.cf virtual resp transport aktivieren
Code:
transport_maps = hash:/path/to/transport
virtual_alias_maps = hash:/path/to/virtual
Danach ein
Code:
postfix stop
postfix start
autoresponder Script
Hier kommt das unter autoreply festgelegt Script. Es handelt sich hierbei um ein einfaches Shellscript, welches den Inhalt der Mail (inkl aller Mailheader) via stdin übergeben bekommt. Zusätzlich erwartet das Script den Sender und den Originalempfänger der E-Mail als Parameter.

Das Script prüft ob die Mail von einer Mailingliste kommt oder sonstige Bedingungen nicht erfüllt. In diesen Fällen wird keine Mail versendet. Bei den Bedingungen habe ich mich bei vacation orientiert
  • Auto-Submitted: header exists with any value except "no"
  • Precedence: header exists with value "junk", "bulk" or "list"
  • The envelope sender
    • begins with "MAILER-DAEMON" (case-insensitive)
    • begins with "LISTSERV" (case-insensitive)
    • begins with "majordomo" (case-insensitive)
    • begins with "owner-" (case-sensitive)
    • contains the string "-request" anywhere within it (case-sensitive)
  • The envelope sender and envelope recipient are the same
  • The envelope recipient is not found in the message To:, Cc: or Bcc: fields.
  • The envelope sender is not found in From-Header
Code als zip autoreply.zip
Code:
#!/bin/bash

# config variables

# logpath MUST be writable for the user running autoreply (check master.cf where the user can be specified)
# the script tries to create the file but depending from the specified position it will be impossible
# for the script to create it.
# The easiest way is to manually create the file and chmod it so the user running autoreply has write privileges on the file
LOG=/var/log/autoreply.log

# exclude list for autoreply. must be valid syntax for egrep command!!
# if the sender of the mail or the receiver of the autoreply match expression then NO autoreply will be sent
EXCLUDE=MY_DOMAIN\|MY_OTHER_DOMAIN\|TOTAL_OTHER_DOMAIN

# path to sendmail program
# for diskstation users /usr/syno/mailstation/sbin/sendmail
MAIL=/usr/sbin/sendmail

# installation path of the script itself and its template files
# note: the trailing slash is VERY important!!
I_PATH=/etc/postfix/autoreply/

case "$2" in
 'webmaster@MY_DOMAIN')
  NAME='Me the webmaster'
  COMPANY='MY COMPANY'
 ;;
 'autoreply-test@MY_DOMAIN')
  NAME='James Bond aka 007'
  COMPANY='MI6 Royalkillers Branch'
  ADDRESS='Swansey Road 110'
  TOWN='Not known'
  COUNTRY='Scotland'
 ;;
esac
touch $LOG > /dev/null 2>&1
[[ $? -ne 0 || ! -w $LOG ]] && echo "$LOG could not be statet. Check path and permissions" && exit 1

while read x1
do
 MSG="$MSG\n$x1"
done

sendReply ()
{
 STR="From: $2 <$2>\n"
 STR=$STR"To: <"$1">\n"
 STR=$STR"Content-Type: multipart/mixed; boundary=\"grenze\"\n"
 STR=$STR"Subject: Ihre Anfrage an / Your request to "$2"\n\n"
 STR=$STR"--grenze\n"
 STR=$STR"Content-Type: multipart/alternative; boundary=\"alternative\"\n"
 eval "TEMPLATE=\"$(cat ${I_PATH}autoreply.txt)\""
 STR=$STR"\n--alternative\n"
 STR=$STR$TEMPLATE
 STR=$STR"\n\n--alternative\n"
 eval "TEMPLATE=\"$(cat ${I_PATH}autoreply.html)\""
 STR=$STR$TEMPLATE
 [[ ! "x$NAME" = 'x' && ! "x$COMPANY" = 'x' ]] && STR="${STR//'VAR_name '/$NAME}" && STR="${STR//VAR_company/ - $COMPANY}"
 [[ "x$NAME" = 'x' || "x$COMPANY" = 'x' ]] && STR="${STR//'VAR_name '/$NAME}" && STR="${STR//VAR_company/$COMPANY}"
 [[ "x$NAME" = 'x' && "x$COMPANY" = 'x' ]] && STR="${STR//'VAR_name '/$NAME}" && STR="${STR//'VAR_company'/$COMPANY}"
 [[ ! "x$ADDRESS" = 'x' && ! "x$TOWN" = 'x' ]] && STR="${STR//'VAR_address '/$ADDRESS}" && STR="${STR//VAR_town/, $TOWN}"
 [[ "x$ADDRESS" = 'x' ||  "x$TOWN" = 'x' ]] && STR="${STR//'VAR_address '/$ADDRESS}" && STR="${STR//VAR_town/$TOWN}"
 [[ "x$ADDRESS" = 'x' && "x$TOWN" = 'x' ]] && STR="${STR//'VAR_address '/$ADDRESS}" && STR="${STR//'VAR_town'/$TOWN}"
 STR="${STR//'VAR_country'/$COUNTRY}"
 STR=$STR"\n\n--alternative--\n\n--grenze\n"
 STR=$STR"Content-Type: message/rfc822\nContent-Disposition: attachment;filename=message.eml;\nContent-Transfer-Encoding: 7bit\n\n$MSG\n\n--grenze--"
 echo -e "$STR" | $MAIL -f "$2" -t "$1"
 if [ $? -eq 0 ] ; then
  SHOW=$(cat /var/log/mail.log | grep '<'$1'>' | awk '{print $6}' | awk -F: '{print $1}')
  OUT=$(echo $SHOW | awk '{print $NF}')
  IN=$(echo $SHOW | awk '{print $(NF-1)}')
  echo -e $(date +"%b %_d %T")" autoreply success: msg to $1 ("$OUT") in response to mail to $2 ("$IN") sent" >> $LOG  && exit 0
 fi
 echo -e $(date +"%b %_d %T")" autoreply error: msg to $1 in response to mail to $2 could NOT  be sent." >> $LOG && exit 1
}
[ ! "x$(echo -e $1 | egrep $EXCLUDE)" = 'x' ] && echo -e $(date +"%b %_d %T")" autoreply dunno: domain in exclude list found in sender-envelope sender=$1 rcpt=$2" >> $LOG 2>&1 && exit 1
[ ! "x$(echo -e $MSG | grep ^From: | egrep $EXCLUDE)" = 'x' ] && echo -e $(date +"%b %_d %T")" autoreply dunno: domain in exclude list found in From-header sender=$1 rcpt=$2" >> $LOG 2>&1 && exit 1
[ "$1" = "$2" ] && echo -e $(date +"%b %_d %T")" autoreply dunno: sender and receiver are the same sender=$1 rcpt=$2" >> $LOG && exit 1
[ "x$(echo -e $MSG | grep -i ^From: | grep $1)" = 'x' ] && echo -e $(date +"%b %_d %T")" autoreply dunno: envelop sender not found in From-header sender=$1 rcpt=$2" >> $LOG && exit 1
[ ! "x$(echo -e $MSG | grep -i ^Auto-Submitted: | grep -iv no)" = 'x' ] && echo -e $(date +"%b %_d %T")" autoreply dunno: msg has auto-submitted headers with a value other than \"no\" sender=$1 rcpt=$2" >> $LOG && exit 1
[ ! "x$(echo -e $MSG | grep -i ^Precedence: | grep -i junk)" = 'x' ] && echo -e $(date +"%b %_d %T")" autoreply dunno: msg has precedence \"junk\" header sender=$1 rcpt=$2" >> $LOG && exit 1
[ ! "x$(echo -e $MSG | grep -i ^Precedence: | grep -i bulk)" = 'x' ] &&  echo -e $(date +"%b %_d %T")" autorepy dunno: msg has precedence header \"bulk\" sender=$1 rcpt=$2" >> $LOG && exit 1
[ ! "x$(echo -e $MSG | grep -i ^Precedence: | grep -i list)" = 'x' ] && echo -e $(date +"%b %_d %T")" autoreply dunno: msg has precedence header with \"list\"sender=$1 rcpt=$2" >> $LOG && exit 1
[ ! "x$(echo $1 | egrep -i mailer-daemon\|listserv\|majordomo\|owner-\|\-request)" = 'x' ] &&  echo -e $(date +"%b %_d %T")" autoreply dunno: msg seems to be from a mailing list sender=$1 rcpt=$2" >> $LOG && exit 1
[ ! "x$(echo -e $MSG | grep -i ^To: | grep $2)" = 'x' ] &&  sendReply $1 $2 "$MSG"
[ ! "x$(echo -e $MSG | grep -i ^Cc: | grep $2)" = 'x' ] &&  sendReply $1 $2 "$MSG"
[ ! "x$(echo -e $MSG | grep -i ^Bcc: | grep $2)" = 'x' ] &&  sendReply $1 $2 "$MSG"
echo -e $(date +"%b %_d %T")" autoreply dunno: rcpt not found in headers (To, Cc or Bcc) sender=$1 rcpt=$2" >> $LOG && exit 1
Kategorien
Mailstation , Postfix

Kommentare