Autoreply mit Postfix

Status
Für weitere Antworten geschlossen.

jahlives

Benutzer
Mitglied seit
19. Aug 2008
Beiträge
18.275
Punkte für Reaktionen
4
Punkte
0
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.

Zum Glück gibt es eine sehr einfache Möglichkeit einen autoresponder direkt am Postfix-Server einzurichten. Dazu muss man Anpassungen in zwei Konfigfiles machen und ein Script haben, welches das Beantworten übernimmt

Aktuellste Version des Codes

Konfiguration

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}
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 an 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.
Code
Code:
  [FONT=verdana]
[/FONT] #!/bin/sh
 
######################################################################
#                                                                    #
# autoreply script for integration into postfix server process       #
#                                                                    #
# Author:     tobi <tobster@brain-force.ch>                          #
# Version:    0.1                                                    #
# Date:       11/08/10                                               #
# License:    GPL Version 3                                          #
#                                                                    #
# History:    * 04/08/10 initial version 0.1 as beta                 #
#             * 06/08/10 minor bug fixes                             #
#             * 10/08/10 support for template files added            #
#             * 11/08/10 using orginial content and subject          #
#             * 11/08/10 version 0.2 as stable                       #
#                                                                    #
# ToDo:       * support for txt and html templates (added in 0.2)    #
#             * use original message and subject (added in 0.2)      #
#             * support for attachments in autoreply (in 0.3)        #
#             * original message as rfc822 attachment (in 0.3)       #
#             * mutlipart/alternative and multipart/mixed (in 0.3)   #
#                                                                    #
# Summary:    A small autoreply script that sends messages on every  #
#             mail received ex if you use a info address and want to #
#             confirm every message that is sent there.              #
#             Some tests are performed before sending the mail:      #
#                                                                    #
#              * is the mail coming from a mailing list?             #
#              * are there typical headers for bulk messages?        #
#              * can the rcpt address been found in msg headers?     #
#                                                                    #
# Usage:      echo msg | autreply sender reciever                    #
# * sender:   sender of the original msg. The one who will receive   #
#             the autoreply                                          #
# * receiver: the receiver of the original msg. Will be used as      #
#             sender of the autoreply message                        #
# * stdin:    on stdin the content of the original msg is expected   #
#                                                                    #
######################################################################
 
if test "$1" = "-h"; then
 echo "*************************************************************"
 echo "*                                                           *"
 echo "* Usage:    autoreply sender reciever                       *"
 echo "* sender:   the original sender of the mail                 *"
 echo "* reciever: the original reciever of the mail               *"
 echo "* stdin:    on stdin the content of the mail is expected    *"
 echo "*                                                           *"
 echo "*************************************************************"
 exit
fi
 
msg=""
log=/opt/var/log/autoreply.log
err=''
touch $log
 
while read x1
do
 msg="$msg\n$x1"
done
 
sendReply ()
{
 mail=/usr/syno/mailstation/sbin/sendmail
 text=$(echo -e "$msg" | /opt/etc/postfix/split.php)
 subject=$(echo -e "$msg" | grep ^Subject: | cut -c9-)
 str="From: $2 <$2>\n"
 str=$str"To: <"$1">\n"
 str=$str"Content-Type: multipart/alternative; boundary=\"grenze\"\n"
 str=$str"Subject: Ihre Anfrage an / Your request to "$2"\n\n"
 str=$str"--grenze\n"
 eval "t=\"$(cat /opt/etc/postfix/autoreply.txt)\""
 str=$str$t
 str=$str"\n--grenze\n"
 eval "t=\"$(cat /opt/etc/postfix/autoreply.html)\""
 str=$str$t
 str=$str"\n--grenze--"
 echo -e "$str" | $mail -f "$2" -t "$1"
 #echo -e $(date +"%b %_d %T")"\tMessage sent: $1\t$2" >> /opt/var/log/autoreply.log
 #echo -e "$str"
 exit
}
 
err=$(echo -e $msg | grep -i ^Auto-Submitted: | grep -iv "no" )
if test $? = 0; then
 echo -e $(date +"%b %_d %T")"\tMessage has Auto-Submitted Headers with a value other than \"no\"\n$1\t$2" >> $log
 exit
fi
 
err=$(echo -e $msg | grep -i ^Precedence: | grep -i "junk")
if test $? = 0; then
 echo -e $(date +"%b %_d %T")"\tMessages has Precedence \"junk\" header\n$1\t$2" >> $log
 exit
fi
 
err=$(echo -e $msg | grep -i ^Precedence: | grep -i "bulk")
if test $? = 0; then
 echo -e $(date +"%b %_d %T")"\tMessages has Precedence header \"bulk\"\n$1\t$2" >> $log
 exit
fi
 
err=$(echo -e $msg | grep -i ^Precedence: | grep -i "list")
if test $? = 0; then
 echo -e $(date +"%b %_d %T")"\tMessage has Precedence header with \"list\"\n$1\t$2" >> $log
 exit
fi
 
err=$(echo $1 | egrep -i mailer-daemon\|listserv\|majordomo\|owner-\|\-request)
if test $? = 0; then
 echo -e $(date +"%b %_d %T")"\tMessage seems to be from a mailing list\n$1\t$2" >> $log
 #echo "$msg\n$1\n$2" > /opt/var/log/autoreply.log
 exit
fi
 
if test "$1" = "$2" ; then
 echo -e $(date +"%b %_d %T")"\tFehler: Sender und Empfaenger sind gleich\n$1\t$2" >> $log
 exit
fi
 
err=$(echo -e $msg | grep -i ^To: | grep "$2")
if test $? = 0; then
 sendReply $1 $2 "$msg"
fi
 
err=$(echo -e $msg | grep -i ^Cc: | grep "$2")
if test $? = 0; then
 sendReply $1 $2 "$msg"
fi
 
err=$(echo -e $msg | grep -i ^Bcc: | grep "$2")
if test $? = 0; then
 sendReply $1 $2 "$msg"
fi
echo -e $(date +"%b %_d %T")"\trcpt not found in headers (To, Cc or Bcc)\n$1\t$2" >> $log
 
Zuletzt bearbeitet:

mastersnow

Benutzer
Mitglied seit
31. Aug 2011
Beiträge
6
Punkte für Reaktionen
0
Punkte
0
Original Mail mitsenden

Ist es möglich die Original E-Mail worauf der Autoreplay ausgelöst wird noch einmal mitzusenden?
 

jahlives

Benutzer
Mitglied seit
19. Aug 2008
Beiträge
18.275
Punkte für Reaktionen
4
Punkte
0
Postfix gibt dem Script den Sender und den Originalempfänger als Parameter via Kommandozeile. Die gesamte Mail wird via stdin an das Script übergeben und steht dem Script in der Variable $msg zur Verfügung. Guck dir mal das Script in meinem Wiki an (http://syno.brain-force.ch/autoresponder_fuer_postfix). Dort verschicke ich die Originalmail als RFC-Attachment mit der Abwesenheitsmeldung
 

mastersnow

Benutzer
Mitglied seit
31. Aug 2011
Beiträge
6
Punkte für Reaktionen
0
Punkte
0
Unbekannte Anlage

Hallo,

das habe ich gestern Abend auch schon gefunden. Ich bekomme dann zwar die E-Mail zurück aber nur mit einer Unbekannten Anlage.
 

jahlives

Benutzer
Mitglied seit
19. Aug 2008
Beiträge
18.275
Punkte für Reaktionen
4
Punkte
0
und ist das Attachment komplett leer? Das benötigte PHP Script (trim.php) hast du und du hast es am richtigen Ort platziert (sprich die Pfadangabe im Code sollte korrekt sein).
 

mastersnow

Benutzer
Mitglied seit
31. Aug 2011
Beiträge
6
Punkte für Reaktionen
0
Punkte
0
trim.php

Das Script liegt an der richtigen Stelle.

Also Outlook Sagt unbekannte Anlage. Wenn ich die Anlage aufmache dann ist sie leer. Kein Absender kein Empfänger usw.
 

jahlives

Benutzer
Mitglied seit
19. Aug 2008
Beiträge
18.275
Punkte für Reaktionen
4
Punkte
0
behauptet ein anderer Client (z.B. Thunderbird) auch, dass das Attachment leer ist? Mach zum Debuggen mal folgendes: Such diese Zeile
Code:
rfc=$(echo -e "$msg" | /opt/etc/postfix/trim.php)
und schreib direkt danach eine weitere Zeile, so dass folgender Code entsteht:
Code:
rfc=$(echo -e "$msg" | /opt/etc/postfix/trim.php)
echo "$rfc" > /tmp/autoreply_debug
danach sollte in der Datei /tmp/autoreply_debug der Inhalt der empfangenen Mail geschrieben werden
 

mastersnow

Benutzer
Mitglied seit
31. Aug 2011
Beiträge
6
Punkte für Reaktionen
0
Punkte
0
Debug

server:/tmp# cat autoreply_debug

server:/tmp#


Wie du siehst ist sie leer!
 

jahlives

Benutzer
Mitglied seit
19. Aug 2008
Beiträge
18.275
Punkte für Reaktionen
4
Punkte
0
Dann musst du einen Schritt zurück und gleich $msg auch dumpen
Code:
while read x1 
do  
 msg="$msg\n$x1" 
done
echo "$msg" > /tmp/autoreply_debug
exit
 

mastersnow

Benutzer
Mitglied seit
31. Aug 2011
Beiträge
6
Punkte für Reaktionen
0
Punkte
0
Debug

Da steht dann die Nachricht drin.

Also muss ein es Problem mit der trim.php geben oder?
 

jahlives

Benutzer
Mitglied seit
19. Aug 2008
Beiträge
18.275
Punkte für Reaktionen
4
Punkte
0
Drum die Frage: Liegt denn trim.php an korrekten Ort und stimmt der Pfad mit dem Code überein?
 

mastersnow

Benutzer
Mitglied seit
31. Aug 2011
Beiträge
6
Punkte für Reaktionen
0
Punkte
0
trim

Ich würde ja sagen:

server:/etc/postfix# cat autoreply | grep trim
rfc=$(echo -e "$msg" | /etc/postfix/trim.php)
server:/etc/postfix# ls -ll | grep trim.php
-rw-r--r-- 1 root root 135 Sep 1 16:05 trim.php
server:/etc/postfix#
 

jahlives

Benutzer
Mitglied seit
19. Aug 2008
Beiträge
18.275
Punkte für Reaktionen
4
Punkte
0
Mach mal ein chmod +x /etc/postfix/trim.php
Die Datei muss ausführbar sein und das ist sie gemäss deinem Print ned
 

jahlives

Benutzer
Mitglied seit
19. Aug 2008
Beiträge
18.275
Punkte für Reaktionen
4
Punkte
0
Aktualisierte Version des Scripts

Sodele ich habe mir den Code auch wieder selber mal installiert und einige Dinge rausgefunden :) Was bei dir sein könnte ist, dass du die bash ned hast. Ich war mir gar ned bewusst, dass ich das damals eigentlich für die Bash geschrieben habe. bash kriegst du via ipkg (und mehr zu ipkg findest du im Wiki). Zudem muss egrep vorhanden sein. Kann aber ned sicher sagen in welchem ipkg Paket das drin ist (könnte coreutils sein). Diese beiden Pakete, also bash und egrep, braucht dieses Script aber in jedem Fall.

Ich habe den Code mal noch ein bisschen überarbeitet. So wird trim.php nicht mehr benötigt. Die Antwort mit der originalanfrage geht bei mir so problemlos raus und kommt auch sauber an :)
Zuerst mal das aktuelle Script
Wichtig:
die Pfade musst du so anpassen, dass es bei dir hinkommt. Das sind Pfade von einem Debian. Zudem musst du sicherstellen, dass der User, der dann autoreply ausführen wird, auch auf das Logfile schreibend zugreifen darf. Das Script sollte nicht als root laufen (glaube auch kaum, dass postfix das zulassen würde) und damit kann der User das File ziemlich sicher ned anlegen. Also das log als root erstellen und chown root:nobody /path/log && chmod 0770 /path/log

Code:
#!/bin/bash

msg=""
log=/var/log/autoreply.log
err=''
touch $log

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

sendReply ()
{
 mail='/usr/sbin/sendmail'
 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 "t=\"$(cat /etc/postfix/autoreply/autoreply.txt)\""
 str=$str"\n--alternative\n"
 str=$str$t
 str=$str"\n\n--alternative\n"
 eval "t=\"$(cat /etc/postfix/autoreply/autoreply.html)\""
 str=$str$t"\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"
 exit
}

err=$(echo -e $msg | grep -i ^Auto-Submitted: | grep -iv "no" )
t=$?
if test $t -eq 0 ; then
 echo -e $(date +"%b %_d %T")"\tMessage has Auto-Submitted Headers with a value other than \"no\"\n$1\t$2" >> $log
 exit
fi

err=$(echo -e $msg | grep -i ^Precedence: | grep -i "junk")
t=$?
if test $t -eq 0 ; then
 echo -e $(date +"%b %_d %T")"\tMessages has Precedence \"junk\" header\n$1\t$2" >> $log
 exit
fi

err=$(echo -e $msg | grep -i ^Precedence: | grep -i "bulk")
t=$?
if test $t -eq 0 ; then
 echo -e $(date +"%b %_d %T")"\tMessages has Precedence header \"bulk\"\n$1\t$2" >> $log
 exit
fi

err=$(echo -e $msg | grep -i ^Precedence: | grep -i "list")
t=$?
if test $t -eq 0 ; then
 echo -e $(date +"%b %_d %T")"\tMessage has Precedence header with \"list\"\n$1\t$2" >> $log
 exit
fi

err=$(echo $1 | egrep -i mailer-daemon\|listserv\|majordomo\|owner-\|\-request)
t=$?
if test $t -eq 0 ; then
 echo -e $(date +"%b %_d %T")"\tMessage seems to be from a mailing list\n$1\t$2" >> $log
 exit
fi

if test "$1" = "$2" ; then
 echo -e $(date +"%b %_d %T")"\tFehler: Sender und Empfaenger sind gleich\n$1\t$2" >> $log
 exit
fi

err=$(echo -e $msg | grep -i ^To: | grep "$2")
t=$?
if test $t -eq 0; then
 sendReply $1 $2 "$msg"
fi

err=$(echo -e $msg | grep -i ^Cc: | grep "$2")
t=$?
if test $t -eq 0; then
 sendReply $1 $2 "$msg"
fi

err=$(echo -e $msg | grep -i ^Bcc: | grep "$2")
t=$?
if test $t -eq 0; then
 sendReply $1 $2 "$msg"
fi
echo -e $(date +"%b %_d %T")"\trcpt not found in headers (To, Cc or Bcc)\n$1\t$2" >> $log

autoreply.txt legt das Template für den Textteil der autoreply Mail fest. Die Leerzeile zwischen letztem Header und Beginn des Inhalts ist unbedingt zu beachten
$1 ist der Sender der Originalmail (also der Empfänger des autoreply) und $2 ist der Empfänger des Originals resp der Sender beim autoreply
Code:
Content-Type: text/plain
Content-Transfer-Encoding: 7bit

Besten Dank fuer Ihre Anfrage
 Ihre Anfrage wird so schnell wie moeglich beantwortet

Thanks for your request,
 it will be answered asap

Gruss / Regards

$2

Anbei der Inhalt ihrer Anfrage / Following the content of your request

autoreply.html legt das Template für den html Teil der autoreply Antwort fest. Wiederum ist die Leerzeile nach dem letzten Header sehr sehr wichtig ;-)
Code:
Content-Type: text/html
Content-Transfer-Encoding: 7bit

<p>Besten Dank für Ihre Anfrage, <br />
 Ihre Anfrage ist angekommen und wird schnellstmöglich beantwortet</p>

<p>Thanks for your request,<br />\
 Your request has been received and will be answered asap</p>

<p>Gruss / Regards<br /><br />
<a href=\"mailto:"$2"\">"$2"</a><br /><br />
Anbei der Inhalt ihrer Anfrage / Following the content of your request
</p>
 
Status
Für weitere Antworten geschlossen.
 

Kaffeautomat

Wenn du das Forum hilfreich findest oder uns unterstützen möchtest, dann gib uns doch einfach einen Kaffee aus.

Als Dankeschön schalten wir deinen Account werbefrei.

:coffee:

Hier gehts zum Kaffeeautomat