Ich möchte einen einfachen SMTP-Server schreiben, der E-Mails aus dem lokalen Netzwerk empfängt und dann folgendes macht:
- E-Mails ohne Anhang werden einfach ignoriert (gelöscht)
- E-Mails mit Anhang werden weiter verarbeitet: Anhang extrahieren und als Datei auf der Festplatte speichern; anschließend ursprüngliche E-Mail verwerfen (löschen)
Ich komme mit dem Modul smtpd bzw. der extrem kurzen Dokumentation nicht klar.
Habe hier auch noch ein Beispiel namens SMTP Mailsink gefunden, aber das macht erstens was anderes und zweitens steige ich nicht richtig durch.
Hat jemand ein paar hilfreiche Tipps?
einfacher SMTP-Server
Ich hab mich durchgewühlt und bin nun ein Stück weiter. Der SMTP-Server steht und empfängt Mails. Die Methode smtpd.SMTPServer.process_message() sieht bei mir erstmal so aus:
Und sie gibt aus:
Ideen dazu?
Code: Alles auswählen
def process_message(self, peer, mailfrom, rcpttos, data):
print peer, mailfrom, rcpttos, data
Ich möchte nun den Anhang extrahieren und ihn unter seinem urprünglichen Dateinamen speichern. Außerdem benötige ich die Empfänger-E-Mail-Adresse.D:\#devroot\Python-Tools\SMTPServer>C:\Programme\Python24\python.exe mail2file.p
y
server started
('127.0.0.1', 1428) from@domain.de ['to@domain.de'] Message-ID: <474D2808.
8040707@domain.de>
Date: Wed, 28 Nov 2007 09:34:16 +0100
From: droptix <from@domain.de>
User-Agent: Thunderbird 2.0.0.9 (Windows/20071031)
MIME-Version: 1.0
To: SMTPServer <to@domain.de>
Subject: Betreff
Content-Type: multipart/mixed;
boundary="------------080205020705070304070307"
This is a multi-part message in MIME format.
--------------080205020705070304070307
Content-Type: text/plain; charset=ISO-8859-15; format=flowed
Content-Transfer-Encoding: 7bit
Text
--------------080205020705070304070307
Content-Type: application/x-shockwave-flash;
name="test_attachment.swf"
Content-Transfer-Encoding: base64
Content-Disposition: inline;
filename="test_attachment.swf"
Q1dTBsg9AAB4nN27dVxVzdc4Ovtw6O4SOHR3q0gJ0pLSSHd3KQdUBMSgU0EQkFS64UgoUtLS
[...]
wQ2u/2DK3yEY3ZHWBeDmhWkxvf9fq/sWhA==
--------------080205020705070304070307--
Ideen dazu?
- gerold
- Python-Forum Veteran
- Beiträge: 5555
- Registriert: Samstag 28. Februar 2004, 22:04
- Wohnort: Oberhofen im Inntal (Tirol)
- Kontaktdaten:
Hallo droptix!
Mit dem mail-Modul kannst du Emails auseinander nehmen.
mfg
Gerold
Mit dem mail-Modul kannst du Emails auseinander nehmen.
mfg
Gerold
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Hat prima funktioniert. Du meintest das Modul email.
Für alle die es interessiert, ich hab es so gelöst:
Wäre noch cool, wenn man die Decodierung "base64" automatisch erkennt... obwohl kann es denn sein dass bei Dateianhängen eine andere Codierung in Frage kommt?
Für alle die es interessiert, ich hab es so gelöst:
Code: Alles auswählen
import email
# [...]
class MyClass(smtpd.SMTPServer):
# [...]
def process_message(self, peer, mailfrom, rcpttos, data):
print "%s Getting email message from %s to %s" % (time.strftime("%Y/%m/%d %H:%M:%S"), mailfrom, ", ".join(rcpttos))
# parse email data
msg = email.message_from_string(data)
if msg.is_multipart():
# extract attachments
for part in msg.walk():
filename = part.get_filename()
if filename:
attachment = part.get_payload()
# write attachment
for r in recipients:
fp = file(filename, "wb")
fp.write(attachment.decode("base64"))
fp.close()
- gerold
- Python-Forum Veteran
- Beiträge: 5555
- Registriert: Samstag 28. Februar 2004, 22:04
- Wohnort: Oberhofen im Inntal (Tirol)
- Kontaktdaten:
sorry, die Hand war schneller als das Hirn.droptix hat geschrieben:Du meintest das Modul email.
Code: Alles auswählen
attachment.get("Content-Transfer-Encoding")
Gerold
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Ah, danke! Werd ich dann gleich testen...
Nochwas anderes: ich würde das kleine Tool gern als Dienst laufen lassen. Unter Unix muss es also die Parameter "start", "restart" und "stop" kennen. Wenn ich das Tool starte, dann wird es ja nie beendet... weil es via Thread in einem Server-Loop hängt.
Wie könnte ich am besten an diese Problematik rangehen? Gibt's dazu gute Literatur/Tutorials im Netz?
Nochwas anderes: ich würde das kleine Tool gern als Dienst laufen lassen. Unter Unix muss es also die Parameter "start", "restart" und "stop" kennen. Wenn ich das Tool starte, dann wird es ja nie beendet... weil es via Thread in einem Server-Loop hängt.
Wie könnte ich am besten an diese Problematik rangehen? Gibt's dazu gute Literatur/Tutorials im Netz?
- gerold
- Python-Forum Veteran
- Beiträge: 5555
- Registriert: Samstag 28. Februar 2004, 22:04
- Wohnort: Oberhofen im Inntal (Tirol)
- Kontaktdaten:
Hallo droptix!droptix hat geschrieben:Unter Unix muss es also die Parameter "start", "restart" und "stop" kennen.
Nein. Nicht dein Programm kennt diese Parameter, sondern das Init-Skript das für dein Programm zuständig ist. Dieses Init-Skript (sieh dir mal /etc/init.d/skeleton an) reagiert dann auf die übergebenen Parameter ("start", "stop",...) und sendet an dein Programm ein Signal. Dein Programm reagiert dann auf dieses Signal. Das übermitteln des Signals übernimmt oft das Programm "start-stop-daemon". Dafür ist es ideal, wenn dein Programm ein PID-File mit der eigenen Prozessnummer hinterlegt. Diese wird dann verwendet um ein Signal an dein Programm zu schicken.
- http://docs.python.org/lib/module-signal.html
- man kill
- man start-stop-daemon
mfg
Gerold
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
-
- Python-Forum Veteran
- Beiträge: 16025
- Registriert: Freitag 20. Juni 2003, 16:30
- Kontaktdaten:
Die für Daemons wichtigen Signale wären vor allem SIGTERM (exit gracefully) und SIGHUP (reload). Man könnte auch SIGKILL dazuzählen, aber da ein Prozess sowieso nicht auf SIGKILL reagieren kann ist es nicht sonderlich wichtig..
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Hab ein Verständnisproblem: Wie kann denn das "isoliert" laufende Programm vom Init-Skript angesprochen werden und darauf reagieren? Ich hätte mir es jetzt wieder nur via SimpleXMLRPCServer (oder eine Art Server basierend auf Sockets) vorstellen können, aber damit schießt man ja gleich mit Kanonen auf Spatzen... Oder man liest ständig eine Datei ein und erwartet dort drin ein Signal, was die Performance sicher beeinträchtigt.gerold hat geschrieben:[Dieses Init-Skript (sieh dir mal /etc/init.d/skeleton an) reagiert dann auf die übergebenen Parameter ("start", "stop",...) und sendet an dein Programm ein Signal. Dein Programm reagiert dann auf dieses Signal.
Kann man sagen: "Schicke Befehl an den Prozess mit der Nummer X"? Und das Programm hinter dem Prozess X kann das Signal empfangen?
-
- User
- Beiträge: 37
- Registriert: Donnerstag 31. März 2005, 09:55
- Wohnort: hennef
- Kontaktdaten:
hab selbst so was gesucht bin aber noch nicht dazu gekommen es zu testen.
demon + init.d script
http://homepage.hispeed.ch/py430/python/daemon.py
http://homepage.hispeed.ch/py430/python/daemon
demon + init.d script
http://homepage.hispeed.ch/py430/python/daemon.py
http://homepage.hispeed.ch/py430/python/daemon
- Rebecca
- User
- Beiträge: 1662
- Registriert: Freitag 3. Februar 2006, 12:28
- Wohnort: DN, Heimat: HB
- Kontaktdaten:
droptix: http://en.wikipedia.org/wiki/Signal_%28computing%29
Wenn du kill oder ctrl-z benutzt, tust du auch nichts anderes, als Signale versenden.
Wenn du kill oder ctrl-z benutzt, tust du auch nichts anderes, als Signale versenden.
Offizielles Python-Tutorial (Deutsche Version)
Urheberrecht, Datenschutz, Informationsfreiheit: Piratenpartei
Urheberrecht, Datenschutz, Informationsfreiheit: Piratenpartei
Ja, aber nur direkt im Programm selber, während es läuft... dort kann ich einen KeyboardInterrupt abfangen. Ich habe quasi einen "Listener" mitlaufen, der ständig danach lauscht, oder?Rebecca hat geschrieben:Wenn du kill oder ctrl-z benutzt, tust du auch nichts anderes, als Signale versenden.
Aber kann ein zweites Programm z.B. ein Ctrl+C Signal an ein laufendes Programm senden?
- Rebecca
- User
- Beiträge: 1662
- Registriert: Freitag 3. Februar 2006, 12:28
- Wohnort: DN, Heimat: HB
- Kontaktdaten:
Falsch: Wenn du in der Shell Ctrl-C drueckst, sendet der Shell-Prozess an deinen Prozess ein Signal. Du bist in der Shell nie "direkt im Programm selber", sie Shell haengt immer dazwischen. Ja, du kannst den Prozessen, die dir gehoeren, verschiedene Signale von anderen Prozessen aus senden.
Aber wie gesagt, lies dir den Wikipedia-Artikel durch, oder die kill-Manpage, oder Python-Dokumentation zu kill, oder...
Aber wie gesagt, lies dir den Wikipedia-Artikel durch, oder die kill-Manpage, oder Python-Dokumentation zu kill, oder...
Offizielles Python-Tutorial (Deutsche Version)
Urheberrecht, Datenschutz, Informationsfreiheit: Piratenpartei
Urheberrecht, Datenschutz, Informationsfreiheit: Piratenpartei
- Rebecca
- User
- Beiträge: 1662
- Registriert: Freitag 3. Februar 2006, 12:28
- Wohnort: DN, Heimat: HB
- Kontaktdaten:
Nachtrag: Probier mal
aus und schau dir an, was das Programm ausgibt. Aber fuer deinen urspruenglichen Zweck sind andere Signale nuetzlicher, wie Leonidas schon sagte.
Code: Alles auswählen
kill -2 <pid eines python-prozesses>
Offizielles Python-Tutorial (Deutsche Version)
Urheberrecht, Datenschutz, Informationsfreiheit: Piratenpartei
Urheberrecht, Datenschutz, Informationsfreiheit: Piratenpartei
Also ich hab mich ein wenig versucht durchzuwühlen, es scheitert aber an ein paar anschaulichen Beispielen...
Ich kann mir nun vorstellen, dass ein Programm ein Signal an einen Prozess sendet. Nun muss aber mein Prozess das Signal noch empfangen und entsprechend reagieren -> dort scheitert es.
Aus anderen Programmiersprachen kenne ich so etwas wie "listener" oder auch "event listener", die z.B. auf Maus- oder Tastendrücke reagieren. Eine vordefinierte (leere) Methode so einer Listener-Klasse kann man überschreiben und dann sinngemäß etwa sowas hier machen:
Auch mit dem Python-Doc-Beispiel komme ich nicht so richtig weiter. Hätte jemand für mich ein anschauliches Beispiel bestehend aus zwei Teilen:
a) Python-Programm, welches in einem Endlos-Loop läuft; bei Signal SIGTERM wird es beendet, bei Signal SIGHUP wird die Endlosschleife verlassen und neu gestartet
b) ein Python-Programm welches ein Signal an a) sendet; ich nehme an b) muss dazu erst a) starten und sich die Prozess-Id merken
Ich kann mir nun vorstellen, dass ein Programm ein Signal an einen Prozess sendet. Nun muss aber mein Prozess das Signal noch empfangen und entsprechend reagieren -> dort scheitert es.
Aus anderen Programmiersprachen kenne ich so etwas wie "listener" oder auch "event listener", die z.B. auf Maus- oder Tastendrücke reagieren. Eine vordefinierte (leere) Methode so einer Listener-Klasse kann man überschreiben und dann sinngemäß etwa sowas hier machen:
Code: Alles auswählen
class Listener():
__signal = None
def listen(self):
if self.__signal == signal.SIGTERM:
# close all running stuff and terminate program
pass
elif self.__signal == signal.SIGHUP:
# close and restart
pass
a) Python-Programm, welches in einem Endlos-Loop läuft; bei Signal SIGTERM wird es beendet, bei Signal SIGHUP wird die Endlosschleife verlassen und neu gestartet
b) ein Python-Programm welches ein Signal an a) sendet; ich nehme an b) muss dazu erst a) starten und sich die Prozess-Id merken
- gerold
- Python-Forum Veteran
- Beiträge: 5555
- Registriert: Samstag 28. Februar 2004, 22:04
- Wohnort: Oberhofen im Inntal (Tirol)
- Kontaktdaten:
Hallo droptix!
mfg
Gerold
Code: Alles auswählen
#!/usr/bin/env python
# -*- coding: iso-8859-15 -*-
import signal
import time
class Signals(object):
canceled = False
reload_it = False
signals = Signals()
def signal_handler(signum, frame):
print 'Signal handler called with signal', signum
if signum == signal.SIGTERM:
signals.canceled = True
elif signum == signal.SIGHUP:
signals.reload_it = True
def main():
signal.signal(signal.SIGTERM, signal_handler)
signal.signal(signal.SIGHUP, signal_handler)
while True:
if signals.canceled:
print "Canceled"
break
if signals.reload_it:
signals.reload_it = False
print "Reloaded"
continue
time.sleep(1)
print "."
if __name__ == "__main__":
main()
Gerold
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
-
- Python-Forum Veteran
- Beiträge: 16025
- Registriert: Freitag 20. Juni 2003, 16:30
- Kontaktdaten:
Also a) war wirklich nicht so schwer.
Den Handler zu SIGTERM habe ich mir gespart, da das Programm beendet wird, auch wenn man nicht darauf reagiert. Wenn man vor dem Beenden Code ausführen will, würde ich eher auf `atexit` zurückgreifen.
b) habe ich mir gespart, stattdessen kill -s HUP `pidof python` verwendet.
Code: Alles auswählen
import signal, time
class Listener(object):
def complain(self, signum, frame):
self.loop = False
def run(self):
signal.signal(signal.SIGHUP, self.complain)
runs = 0
while True:
runs += 1
print "Starting run %d" % runs
self.loop = True
while self.loop:
time.sleep(1)
Listener().run()
b) habe ich mir gespart, stattdessen kill -s HUP `pidof python` verwendet.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Hallo, Gerold!
In Deinem Beispiel leuchtet mir die Objektorientierung nicht ein. Wenn man eine Klasse Signals schafft, sollte man dann nicht signal_handler als Methode dieser Klasse konstruieren anstatt als globale Funktion? Wenn man aber doch die globale Funktion verwendet, kann man dann nicht auf Signals verzichten und die Klassenattribute als globale Variablen definieren? Man hat ja mit signals sowieso eine globale Variable?
MfG
HWK
In Deinem Beispiel leuchtet mir die Objektorientierung nicht ein. Wenn man eine Klasse Signals schafft, sollte man dann nicht signal_handler als Methode dieser Klasse konstruieren anstatt als globale Funktion? Wenn man aber doch die globale Funktion verwendet, kann man dann nicht auf Signals verzichten und die Klassenattribute als globale Variablen definieren? Man hat ja mit signals sowieso eine globale Variable?
MfG
HWK
- gerold
- Python-Forum Veteran
- Beiträge: 5555
- Registriert: Samstag 28. Februar 2004, 22:04
- Wohnort: Oberhofen im Inntal (Tirol)
- Kontaktdaten:
Hallo HWK!HWK hat geschrieben:In Deinem Beispiel leuchtet mir die Objektorientierung nicht ein.
Mein Beispiel hat mit OO nichts am Hut. Und globale Variablen? Kenn ich nicht!
lg
Gerold
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.