Mailversand per os.system()

Python auf Einplatinencomputer wie Raspberry Pi, Banana Pi / Python für Micro-Controller
Benutzeravatar
Mesquita
User
Beiträge: 15
Registriert: Montag 7. Januar 2019, 15:22

Hallo User,

ich möchte aus einem Skript heraus eine Mail versenden. Dazu teste ich gerade folgenden Code:

Code: Alles auswählen

os.system('echo “Inhalt der Mail” | mail -s “Betreff der Mail” empfaengeradresse')
Der Mailversand funktioniert von der Konsole und aus dem Skript heraus. Der Sinn der Mail soll aber sein, dass der Inhalt einer Variable (Sting) aus dem Skript versendet wird. Wie kann ich den Inhalt der String-Variable mittels mail als Inhalt der Mail versenden? Ich recherchierte, fand aber keinen Ansatz.

Thomas
Benutzeravatar
__blackjack__
User
Beiträge: 13080
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

`os.system()` sollte man sowieso nicht mehr verwenden, in der Dokumentation wird auch auf das `subprocess`-Modul verwiesen. Und da kannst Du die `run()`-Funktion verwenden. Ungetestet:

Code: Alles auswählen

subprocess.run(['mail', '-s', 'Betreff der Mail', 'empfängeradresse'], input='Inhalt der Mail', check=True)
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
Mesquita
User
Beiträge: 15
Registriert: Montag 7. Januar 2019, 15:22

Hallo blackjack,

danke für Deine Antwort. Sobald ich das Modul subprocess:

Code: Alles auswählen

subprocess.run(['mail', '-s', 'Betreff der Mail', '***@***.com'], input='Inhalt der Mail', check=True)

einbinde, kommt folgende Fehlermeldung:

Code: Alles auswählen

subprocess.run(['mail', '-s', 'Betreff der Mail', '***@***.com'], input='Inhalt der Mail', check=True)
AttributeError:'module' object has no attribute 'run'
Sollte es an der Python 2.7.13 liegen oder warum findet er "run" nicht?

Thomas
__deets__
User
Beiträge: 14529
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ja, das ist eine alte Python-Version. Du solltest tatsaechlich auf Python3 umsteigen.
Benutzeravatar
__blackjack__
User
Beiträge: 13080
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Unter Python 2.7 musst Du ein `Popen`-Objekt erstellen, die Standardeingabe als Pipe definieren und den Inhalt dann über die `communicate()`-Methode übergeben.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
Mesquita
User
Beiträge: 15
Registriert: Montag 7. Januar 2019, 15:22

Guten Abend,

die Umstellung auf Python3 habe ich vorghenommen. Das Ergebnis beim gleichen Aufruf ist:

Code: Alles auswählen

subprocess.run('mail', '-s', 'Betreff', '***@***', input='Hier soll der Inhalt der Variable stehen', check=True)
  File "/usr/lib/python3.5/subprocess.py", line 383, in run
    with Popen(*popenargs, **kwargs) as process:
TypeError: __init__() got multiple values for argument 'stdin'
Handelt es sich um einen Syntaxfehler in der Standardeingabe stdin?

Thomas
Benutzeravatar
Mesquita
User
Beiträge: 15
Registriert: Montag 7. Januar 2019, 15:22

Hallo blackjack,

ich würde gern mit Python3 weiterarbeiten, da habe ich auch Unterlagen/Bücher/Lehrmaterial dazu.

Thomas
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

Schau mal genau, was __blackjack__ geschrieben hat. Außerdem sollte input noch binär sein, oder ein encoding= angegeben werden.
Benutzeravatar
Mesquita
User
Beiträge: 15
Registriert: Montag 7. Januar 2019, 15:22

Hallo blackjack,

trifft dies auch für Python 3.5 zu?
__blackjack__ hat geschrieben: Mittwoch 9. Januar 2019, 17:03 Unter Python 2.7 musst Du ein `Popen`-Objekt erstellen, die Standardeingabe als Pipe definieren und den Inhalt dann über die `communicate()`-Methode übergeben.
Thomas
__deets__
User
Beiträge: 14529
Registriert: Mittwoch 14. Oktober 2015, 14:29

Dafür gibt es subprocess.run, wie ursprünglich beschrieben. Da musst du allerdings auch noch capture_output=True angeben, und dann auf der dem Rückgabeobjekt stdout auslesen:

o = subprocess.run(..., capture_output=True)
print(o.stdout)
Benutzeravatar
__blackjack__
User
Beiträge: 13080
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Mesquita: Jain. Das geht natürlich auch in Python 3.5 aber da gibt's halt `run()`.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
__deets__
User
Beiträge: 14529
Registriert: Mittwoch 14. Oktober 2015, 14:29

Das sehr praktische capture_output leider wohl erst ab 3.7.
Benutzeravatar
Mesquita
User
Beiträge: 15
Registriert: Montag 7. Januar 2019, 15:22

Sorry, ich denke ich wage mich zu weit vor. Meine Kenntnisse sind noch sehr dünn bzw. alt. In den Büchern steht zu subprocess noch garnichts, sind aber gerade mal 1 Monat alt. Wie erzeugt man ein Popen Objekt?

Thomas
__deets__
User
Beiträge: 14529
Registriert: Mittwoch 14. Oktober 2015, 14:29

p = subprocess.Popen(....)

Oder eben subprocess.run, das noch ein paar nette Zusatzfunktionen bereitstellt wie zB check, mit dem man dann gleich einen Fehler bekommt, wenn der Prozess mit einem Fehlercode zurueckgekehrt ist.

Hast du dir die Dokumentation dazu mal angeschaut?

https://docs.python.org/3/library/subpr ... rocess.run
Benutzeravatar
Mesquita
User
Beiträge: 15
Registriert: Montag 7. Januar 2019, 15:22

Hallo deets,

die Doku habe ich mir angesehen, komme aber trotzdem damit nicht klar.

Code: Alles auswählen

p=subprocess.Popen(['mail', '-s', 'Betreff', '***@***.com'], stdin=PIPE)
print(p.stdout)
Das Ergebnis sieht folgendermaßen aus:

Code: Alles auswählen

NameError: name 'PIPE' is not defined
Mir fehlt einfach der Zugang, die Erfahrung. Nehme ich mir zu viel vor? Bitte verliert nicht die Geduld mit mir, ich kann auch nur unregelmäßig daran arbeiten. Das System muss im Ausland dann seine Dienste tun.

Thomas
Benutzeravatar
__blackjack__
User
Beiträge: 13080
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Mesquita: Es gibt eine Handvoll eingebaute Objekte deren Namen man einfach so verwenden kann. `PIPE` gehört nicht dazu, das ist im `subprocess`-Modul definiert. Also muss man das Modul importieren und die Konstante über das Modul referenzieren, wie Du das ja mit `Popen` auch machst, oder man muss es explizit mit ``from subprocess import PIPE`` importieren. Das gilt ganz generell.

Du solltest übrigens gar nicht erst mit einbuchstabigen Namen anfangen. `process` oder `mail_process` wären deutlich bessere Namen. Und nach dem Start des Prozesses, musst Du dann noch den Mailinhalt in das Dateiobjekt `mail_process.stdin` schreiben und danach schliessen, damit das ``mail``-Programm weiss, das die Daten komplett sind. Und dann mit der `wait()`-Methode auf das Ende des Prozesses warten.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
Mesquita
User
Beiträge: 15
Registriert: Montag 7. Januar 2019, 15:22

Guten Morgen blackjack,

danke für die Hinweise. Ich arbeite an meinem kleinen Skript weiter und melde mich sobald ich wieder mal am "Ende" bin. Zuerst versuche ich den Hinweis "das Modul importieren und die Konstante über das Modul referenzieren, wie Du das ja mit `Popen` auch machst" zu beleuchten.

Thomas
Benutzeravatar
Mesquita
User
Beiträge: 15
Registriert: Montag 7. Januar 2019, 15:22

Hallo blackjack,

ich kann einen Erfolg vermelden, die Mail geht mit gewünschtem Inhalt raus, allerdings nicht mit subprocess. Meine Kenntnisse sind nicht so umfassend, sodass ich die Hinweise nicht erfolgreich umsetzen konnte. Mein Ausweg ist die Verwendung von smtplib mit server.sendmail(). Liege ich bei server.sendmail() richtig, kann die Funktion keinen Betreff verarbeiten? Ist nur ein Schönheitsfehler.

Der nächste Punkt für mich ist das Handling einer Variable. Ich ermittle im Skript einen Laufzeitwert und möchte diesen beim nächsten Aufruf erneut überprüfen mit dem dann ermittelten Laufzeitwert. Dies bedeutet eine Zwischenspeicherung. Traditionell könnte man den Wert in eine Datei schreiben und ablegen. Allerdings möchte ich die Zugriffe auf den Datenträger reduzieren und dies im Arbeitsspeicher oä machen. Gibt es eine Möglichkeit den Inhalt einer Variable außerhalb des Scriptes zu erhalten ohne den Datenträger zu nutzen? Bei einem Neustart wäre dieser dann verloren, wäre auch kein Problem.

Thomas
__deets__
User
Beiträge: 14529
Registriert: Mittwoch 14. Oktober 2015, 14:29

Hast du dein System sonst auch auf keine Schreibvorgaenge getunt? Wenn nicht kommt es nun darauf auch nicht an. Ansonsten bietet sich ein tmpfs an, zB fuer /tmp - da hast du dann eine RAM-Disk.
Benutzeravatar
__blackjack__
User
Beiträge: 13080
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Mesquita: `sendmail()` versendet eine komplette Mail als Bytes. Wie sollte da ein Betreff bei der Funktion noch Sinn machen? Der steht ja schon in den Bytes. Und wenn er da nicht steht, machst Du etwas falsch. Wie kommen die Bytes denn bei Dir zustande und warum verwendest Du `sendmail()` und nicht `send_message()`? Das bedeutet doch das Du irgend etwas selbst machst, was diese Methode schon leistest, oder das Du etwas nicht machst, was Du besser machen solltest.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Antworten