Rheinwerk Computing < openbook >

 
Inhaltsverzeichnis
1 Einleitung
2 Die Programmiersprache Python
Teil I Einstieg in Python
3 Erste Schritte im interaktiven Modus
4 Der Weg zum ersten Programm
5 Kontrollstrukturen
6 Dateien
7 Das Laufzeitmodell
8 Funktionen, Methoden und Attribute
9 Informationsquellen zu Python
Teil II Datentypen
10 Das Nichts – NoneType
11 Operatoren
12 Numerische Datentypen
13 Sequenzielle Datentypen
14 Zuordnungen
15 Mengen
16 Collections
17 Datum und Zeit
18 Aufzählungstypen – Enum
Teil III Fortgeschrittene Programmiertechniken
19 Funktionen
20 Modularisierung
21 Objektorientierung
22 Ausnahmebehandlung
23 Iteratoren
24 Kontextobjekte
25 Manipulation von Funktionen und Methoden
Teil IV Die Standardbibliothek
26 Mathematik
27 Kryptografie
28 Reguläre Ausdrücke
29 Schnittstelle zu Betriebssystem und Laufzeitumgebung
30 Kommandozeilenparameter
31 Dateisystem
32 Parallele Programmierung
33 Datenspeicherung
34 Netzwerkkommunikation
35 Debugging und Qualitätssicherung
36 Dokumentation
Teil V Weiterführende Themen
37 Anbindung an andere Programmiersprachen
38 Distribution von Python-Projekten
39 Grafische Benutzeroberflächen
40 Python als serverseitige Programmiersprache im WWW – ein Einstieg in Django
41 Wissenschaftliches Rechnen
42 Insiderwissen
43 Von Python 2 nach Python 3
A Anhang
Stichwortverzeichnis

Download:
- Beispielprogramme, ca. 464 KB

Jetzt Buch bestellen
Ihre Meinung?

Spacer
<< zurück
Python 3 von Johannes Ernesti, Peter Kaiser
Das umfassende Handbuch
Buch: Python 3

Python 3
Pfeil 34 Netzwerkkommunikation
Pfeil 34.1 Socket API
Pfeil 34.1.1 Client-Server-Systeme
Pfeil 34.1.2 UDP
Pfeil 34.1.3 TCP
Pfeil 34.1.4 Blockierende und nicht-blockierende Sockets
Pfeil 34.1.5 Erzeugen eines Sockets
Pfeil 34.1.6 Die Socket-Klasse
Pfeil 34.1.7 Netzwerk-Byte-Order
Pfeil 34.1.8 Multiplexende Server – selectors
Pfeil 34.1.9 Objektorientierte Serverentwicklung – socketserver
Pfeil 34.2 URLs – urllib
Pfeil 34.2.1 Zugriff auf entfernte Ressourcen – urllib.request
Pfeil 34.2.2 Einlesen und Verarbeiten von URLs – urllib.parse
Pfeil 34.3 FTP – ftplib
Pfeil 34.3.1 Mit einem FTP-Server verbinden
Pfeil 34.3.2 FTP-Kommandos ausführen
Pfeil 34.3.3 Mit Dateien und Verzeichnissen arbeiten
Pfeil 34.3.4 Übertragen von Dateien
Pfeil 34.4 E‐Mail
Pfeil 34.4.1 SMTP – smtplib
Pfeil 34.4.2 POP3 – poplib
Pfeil 34.4.3 IMAP4 – imaplib
Pfeil 34.4.4 Erstellen komplexer E‐Mails – email
Pfeil 34.5 Telnet – telnetlib
Pfeil 34.5.1 Die Klasse Telnet
Pfeil 34.5.2 Beispiel
Pfeil 34.6 XML-RPC
Pfeil 34.6.1 Der Server
Pfeil 34.6.2 Der Client
Pfeil 34.6.3 Multicall
Pfeil 34.6.4 Einschränkungen
 
Zum Seitenanfang

34.4    E‐Mail Zur vorigen ÜberschriftZur nächsten Überschrift

In diesem Abschnitt werden wir Module der Standardbibliothek vorstellen, die es ermöglichen, mit einem E‐Mail-Server zu kommunizieren, das heißt, E‐Mails von diesem abzuholen bzw. E‐Mails über den Server zu versenden.

Das Versenden einer E‐Mail erfolgt über einen sogenannten SMTP-Server, mit dem über ein gleichnamiges Protokoll kommuniziert werden kann. Im ersten Unterabschnitt werden wir Ihnen deshalb das Modul smtplib der Standardbibliothek vorstellen, das dieses Kommunikationsprotokoll implementiert.

Für das Herunterladen einer empfangenen E‐Mail gibt es zwei verbreitete Möglichkeiten: das POP3- und das IMAP4-Protokoll. Beide können mit dem jeweiligen Modul poplib bzw. imaplib verwendet werden.

Im letzten Abschnitt wird das Modul email der Standardbibliothek besprochen, das es über die MIME-Codierung ermöglicht, beliebige Dateien (üblicherweise Bilder oder Dokumente) mit der E‐Mail zu versenden.

 
Zum Seitenanfang

34.4.1    SMTP – smtplib Zur vorigen ÜberschriftZur nächsten Überschrift

Das SMTP-Protokoll (für Simple Mail Transfer Protocol) wird zum Versenden einer E‐Mail über einen SMTP-Server verwendet. Das SMTP-Protokoll ist ähnlich wie FTP ein textbasiertes, menschenlesbares Protokoll. Ursprünglich bot das SMTP-Protokoll keine Möglichkeit zur Authentifizierung des angemeldeten Benutzers, beispielsweise durch Benutzernamen und Passwort. Dies war bei der rasanten Entwicklung des Internets schnell nicht mehr tragbar, und so wurde das SMTP-Protokoll um den ESMTP-Standard (Extended SMTP) erweitert. Tabelle 34.9 listet die wichtigsten SMTP-Befehle in der Reihenfolge ihrer Benutzung in einer SMTP-Sitzung auf und erklärt sie kurz.

Befehl Beschreibung
HELO Startet eine SMTP-Sitzung.
EHLO Startet eine ESMTP-Sitzung.
MAIL FROM Leitet das Absenden einer E‐Mail ein. Diesem Kommando wird die Absenderadresse beigefügt.
RCPT TO Fügt einen Empfänger der E‐Mail hinzu. (RCPT steht für Recipient, dt. »Empfänger«.)
DATA Mit diesem Kommando wird der Inhalt der E‐Mail angegeben und die Mail schließlich verschickt.
QUIT Beendet die SMTP- bzw. ESMTP-Sitzung.

Tabelle 34.9    SMTP-Befehle

Das Modul smtplib enthält im Wesentlichen eine Klasse namens SMTP. Nachdem diese Klasse instanziiert wurde, läuft über sie alle weitere Kommunikation mit dem Server.

SMTP([host, port, local_hostname, timeout, source_address])

Beim Erzeugen der Klasse SMTP können optional bereits die Verbindungsdaten zum SMTP-Server übergeben werden. Der Port muss nur explizit angegeben werden, wenn er sich vom SMTP-Standardport 25 unterscheidet.

Als dritter Parameter kann der Domainname des lokalen Hosts übergeben werden. Dieser wird dem SMTP-Server als Identifikation im ersten gesendeten Kommando übermittelt. Wenn der Parameter local_hostname nicht angegeben wird, wird versucht, den lokalen Hostnamen automatisch zu ermitteln.

Für den vierten Parameter können Sie einen speziellen Timeout-Wert in Sekunden übergeben, der bei der Verbindung zum SMTP-Server berücksichtigt wird. Wenn Sie timeout nicht angeben, wird ein Standardwert verwendet.

Mit source_address wird die Herkunftsadresse, die bei der Verbindung verwendet werden soll, als Tupel im Format (ip, port) angegeben. Um die Beispiele der folgenden Abschnitte nachvollziehen zu können, muss das Modul smtplib eingebunden werden und eine Instanz der Klasse SMTP mit dem Namen s existieren:

>>> import smtplib
>>> s = smtplib.SMTP("smtp.server.de")
[»]  Hinweis

Die SMTP-Klasse lässt sich mit dem with-Statement verwenden:

with smtplib.SMTP("smtp.server.de") as s:
s.login("Benutzername", "Passwort")

Eine Verbindung aufbauen und beenden

Das Aufbauen einer SMTP-Verbindung erfolgt in der Regel in zwei Schritten: dem eigentlichen Verbindungsaufbau und dem Login. Im Modul smtplib werden diese beiden Schritte durch die Funktionen connect und login repräsentiert:

>>> s.connect("smtp.server.de", 25)
(220, 'Die Botschaft des Servers')
>>> s.login("Benutzername", "Passwort")
(235, '2.0.0 Authentication successful')

Die Angabe des Ports bei connect ist optional und kann weggelassen werden, wenn es sich um den SMTP-Standardport 25 handelt.

Zum Beenden einer SMTP-Verbindung wird die Funktion quit aufgerufen.

Eine E‐Mail versenden

Zum Versenden einer E‐Mail über SMTP existiert die Funktion sendmail mit der folgenden Schnittstelle:

sendmail(from_addr, to_addrs, msg, [mail_options, rctp_options])

Beachten Sie, dass die SMTP-Instanz dafür an einem SMTP-Server angemeldet und zumeist auch authentifiziert sein muss.

Die ersten beiden Parameter enthalten die E‐Mail-Adressen des Absenders (from_addr) bzw. eine Liste der E‐Mail-Adressen der Empfänger (to_addr). Als E‐Mail-Adresse wird dabei ein String des folgenden Formats bezeichnet:

Vorname Nachname <em@il.addr>

Alternativ kann auch nur die E‐Mail-Adresse im String stehen.

Als dritten Parameter, msg, übergeben Sie den Text der E‐Mail. Hier werden auch weitere Angaben wie beispielsweise der Betreff der E‐Mail definiert. Wie so etwas genau aussieht und welche Möglichkeiten Python bietet, diesen Header komfortabel zu erzeugen, erfahren Sie in Abschnitt 34.4.4, »Erstellen komplexer E‐Mails – email«.

Die Methode sendmail gibt stets ein Dictionary zurück, in dem alle Empfänger, die vom SMTP-Server zurückgewiesen wurden, als Schlüssel enthalten sind und der jeweilige Error-Code mit Fehlerbezeichnung als Wert aufgeführt ist. Wenn alle Empfänger die E‐Mail bekommen haben, ist das zurückgegebene Dictionary leer.

[»]  Hinweis

Der Text einer E‐Mail darf nur aus ASCII-Zeichen bestehen. Um auch andere Zeichen und insbesondere auch Binärdaten verschicken zu können, bedient man sich der sogenannten MIME-Codierung, die wir in Abschnitt 34.4.4, »Erstellen komplexer E‐Mails – email«, behandeln werden.

Über die optionalen Parameter mail_options und rcpt_options kann je eine Liste von Strings übergeben werden, die Optionen des ESMTP-Standards (Extended SMTP) enthalten. Die für mail_options übergebenen Optionen werden dem Kommando MAIL FROM angefügt, während die für rcpt_options übergebenen Optionen dem Kommando RCPT TO angehängt werden.

Beispiel

Nachdem Sie die wichtigsten Methoden einer SMTP-Instanz kennengelernt haben, folgt nun ein kleines Beispiel, in dem zu einem SMTP-Server verbunden wird, um zwei E‐Mails an verschiedene Empfänger zu verschicken:

>>> smtp = smtplib.SMTP("smtp.server.de", 25)
>>> smtp.login("Benutzername", "Passwort")
(235, '2.0.0 Authentication successful')
>>> smtp.sendmail(
... "Peter Kaiser <kaiser@python-buch.de>",
... "Johannes Ernesti <ernesti@python-buch.de>",
... "Dies ist der Text")
{}
>>> smtp.sendmail(
... "Peter Kaiser <kaiser@python-buch.de>",
... ["ernesti@python-buch.de", "kaiser@python-buch.de"],
... "Dies ist der Text")
{}
>>> smtp.quit()

Bei der ersten E‐Mail wurden die vollen Namen des Absenders bzw. des Empfängers angegeben. Das zweite Beispiel zeigt, dass auch die E‐Mail-Adresse allein reicht, und demonstriert, wie eine E‐Mail an mehrere Empfänger versandt werden kann.

 
Zum Seitenanfang

34.4.2    POP3 – poplib Zur vorigen ÜberschriftZur nächsten Überschrift

Nachdem anhand von smtplib erläutert wurde, wie E‐Mails über einen SMTP-Server versandt werden können, besprechen wir in diesem Abschnitt das Modul poplib der Standardbibliothek. Dieses Modul implementiert das POP3-Protokoll (Post Office Protocol Version 3). Bei POP3 handelt es sich um ein Protokoll, das dazu verwendet wird, auf einem POP3-Server gespeicherte E‐Mails einzusehen und abzuholen. Das POP3-Protokoll steht damit in Konkurrenz zu IMAP4, dessen Benutzung mit der imaplib im nächsten Abschnitt besprochen wird.

Tabelle 34.10 listet die wichtigsten POP3-Kommandos mit ihrer Bedeutung auf. Die Befehle stehen dabei in der Reihenfolge, wie sie in einer üblichen POP3-Sitzung verwendet werden.

Befehl Beschreibung
USER Überträgt den Benutzernamen zur Authentifizierung auf dem Server.
PASS Überträgt das Passwort zur Authentifizierung auf dem Server.
STAT Liefert den Status des Posteingangs, beispielsweise die Anzahl der neu eingegangenen E‐Mails.
LIST Liefert Informationen zu einer bestimmten E‐Mail des Posteingangs.
RETR Überträgt eine bestimmte E‐Mail.
DELE Löscht eine bestimmte E‐Mail.
RSET Widerruft alle anstehenden Löschvorgänge.*
QUIT Beendet die POP3-Sitzung.
* Löschvorgänge werden gepuffert und erst am Ende der Sitzung ausgeführt.

Tabelle 34.10    POP3-Befehle

Wie bereits beim Modul smtplib ist im Modul poplib im Wesentlichen die Klasse POP3 enthalten, die instanziiert werden muss, bevor Operationen auf einem POP3-Server durchgeführt werden können. Die Schnittstelle des Konstruktors wird im folgenden Abschnitt beschrieben.

POP3(host, [port, timeout])

Dem Konstruktor der Klasse POP3 wird der Hostname des Servers übergeben, zu dem verbunden werden soll. Optional kann ein Port angegeben werden, wenn dieser sich vom voreingestellten Standardport 110 unterscheiden soll. Zusätzlich kann ein Timeout in Sekunden angegeben werden, der bei der Verbindung zum Server berücksichtigt wird.

Um die in den folgenden Abschnitten vorgestellten Beispiele ausführen zu können, muss zum einen das Modul poplib eingebunden sein und zum anderen eine Instanz der Klasse POP3 mit dem Namen pop existieren:

>>> import poplib
>>> pop = poplib.POP3("pop.server.de")

Für die meisten Beispiele muss diese Instanz außerdem mit einem POP3-Server verbunden und bei diesem authentifiziert sein.

Eine Verbindung aufbauen und beenden

Nach der Instanziierung der Klasse POP3, bei der bereits zum Zielserver verbunden wird, folgt in der Regel ein Authentifizierungsschritt. Dazu müssen die Methoden user und pass_ der POP3-Instanz aufgerufen werden:

>>> pop.user("Benutzername")
b'+OK'
>>> pop.pass_("Passwort")
b'+OK logged in.'
[»]  Hinweis

Der bevorzugte Name pass für die Passwort-Methode ist in Python bereits mit einem Schlüsselwort belegt. In solchen Fällen wird an den belegten Namen häufig ein Unterstrich angehängt.

Nachdem das Passwort vom Server akzeptiert worden ist, darf auf den Posteingang zugegriffen werden. Dieser ist bis zum Aufruf von quit für andere Login-Versuche gesperrt:

>>> pop.quit()
b'+OK Logging out'

Vorhandene E‐Mails auflisten

Nach der Authentifizierung bei einem POP3-Server können die dort gespeicherten E‐Mails eingesehen und gelöscht werden. Dazu können Sie sich zunächst mithilfe der Methoden stat und list einen Überblick über die vorhandenen E‐Mails verschaffen.

Die Methode stat gibt den Status des Posteingangs zurück. Das Ergebnis ist ein Tupel mit zwei ganzen Zahlen: der Anzahl der enthaltenen Nachrichten und der Größe des Posteingangs in Byte.

>>> pop.stat()
(1, 623)

In diesem Fall befindet sich eine E‐Mail im Posteingang, und die Gesamtgröße des Posteingangs beläuft sich auf 623 Byte.

Die Methode list gibt eine Liste der im Posteingang liegenden Mails zurück. Der Rückgabewert dieser Methode ist ein Tupel der folgenden Form:

(antwort, [b"mailID länge", ...], datlen)

Dabei enthält das Tupel als erstes Element den Antwort-String des Servers und als zweites Element eine Liste von bytes-Strings, die je für eine E‐Mail des Posteingangs stehen. Der String enthält zwei Angaben: Die Angabe mailID ist die laufende Nummer der Mail, eine Art Index, und laenge ist die Gesamtgröße der Mail in Byte. In Bezug auf den Index sollten Sie beachten, dass alle E‐Mails auf dem Server fortlaufend von 1 an indiziert werden.

>>> pop.list()
(b'+OK […].', [b'1 623'], 7)

Das erste Element des Tupels (antwort) enthält nicht den vollständigen Antwort-String des Servers, denn die Informationen, die zum zweiten Element des Tupels aufbereitet wurden, wurden aus antwort entfernt. Um dennoch die komplette Länge der Serverantwort berechnen zu können, existiert das dritte Element des Tupels (datlen). Dieses referenziert die Länge des Datenbereichs der Antwort des Servers. Damit entspräche len(antwort) + datlen der Gesamtgröße des vom Server tatsächlich gesendeten Antwort-Strings.

Optional kann die laufende Nummer einer E‐Mail angegeben werden, über die nähere Informationen zurückgegeben werden sollen. In diesem Fall gibt die Methode einen bytes-String des Formats b"+OK mailID länge" zurück:

>>> pop.list(1)
b'+OK 1 623'

E‐Mails abrufen und löschen

Mithilfe der Methode retr lässt sich eine E‐Mail abrufen. Diese Methode gibt den Inhalt der E‐Mail in Form des folgenden Tupels zurück:

(antwort, zeilen, länge)

Das erste Element des Tupels entspricht dem Antwort-String des Servers.[ 150 ](Im Antwort-String ist von »623 octets« die Rede. Mit Octets (dt. »Achtergruppen«) sind Bytes gemeint. ) An zweiter Stelle steht eine Liste von bytes-Strings, die je eine Zeile der E‐Mail inklusive des E‐Mail-Headers enthalten. Das letzte Element des Tupels ist die Größe der E‐Mail in Byte.

Im folgenden Beispiel wird die E‐Mail mit der laufenden Nummer 1 vom Server abgerufen:

>>> pop.retr(1)
(b'+OK 623 octets follow.', […], 623)

Anstelle des Auslassungszeichens stünde eine Liste von Strings, die die Zeilen der vollständigen E‐Mail enthält.

In analoger Art und Weise funktioniert das Löschen einer E‐Mail über die Methode dele:

>>> pop.dele(1)
b'+OK Deleted.'
[»]  Hinweis

Beachten Sie, dass die meisten Server Löschbefehle puffern und erst nach Aufruf der Methode quit tatsächlich ausführen.

In einem solchen Szenario kann die Methode rset aufgerufen werden, um alle anstehenden Löschvorgänge zu verwerfen.

Beispiel

Das folgende Beispielprogramm verwendet das Modul poplib dazu, alle E‐Mails von einem POP3-Server abzuholen und auf dem Bildschirm anzuzeigen:

import poplib
pop = poplib.POP3("pop.server.de")
pop.user("benutzername")
pop.pass_("passwort")
for i in range(1, pop.stat()[0]+1):
for zeile in pop.retr(i)[1]:
print(zeile)
print("***")
pop.quit()

Zunächst wird eine Instanz der Klasse POP3 erzeugt, und das Programm meldet sich mit den Methoden user und pass_ beim POP3-Server an. Der Ausdruck pop.stat()[0] liefert die Zahl der Mails, die sich im Posteingang befinden. In der for-Schleife werden also alle Mail-Indizes durchlaufen. Die Indizierung der E‐Mails im Posteingang beginnt mit 1.

In der inneren Schleife wird die jeweils aktuelle Mail mit dem Index i durch Aufruf der Methode retr heruntergeladen. Das zweite Element, also das mit dem Index 1 des von dieser Methode zurückgegebenen Tupels, enthält eine Liste mit allen Zeilen des Mail-Inhalts. Diese Liste wird in der Schleife durchlaufen, und es wird jeweils die aktuelle Zeile ausgegeben.

[»]  Hinweis

Aus Gründen der Übersichtlichkeit wurde im Beispielprogramm auf jegliche Fehlerbehandlung verzichtet. In einem fertigen Programm sollten Sie prüfen, ob die Verbindung zum Server hergestellt werden konnte und ob die Authentifizierung erfolgreich war.

 
Zum Seitenanfang

34.4.3    IMAP4 – imaplib Zur vorigen ÜberschriftZur nächsten Überschrift

Das Modul imaplib stellt die Klasse IMAP4 zur Verfügung, mit deren Hilfe Sie eine Verbindung zu einem IMAP4-Server herstellen und mit diesem kommunizieren. Das IMAP4-Protokoll (Internet Message Access Protocol 4) ist ähnlich wie das POP3-Protokoll zur Verwaltung von E‐Mails auf einem Mail-Server gedacht. Anders als bei POP3 verbleiben die E‐Mails bei IMAP4 zumeist auf dem Mail-Server, was den Vorteil hat, dass man von überall – beispielsweise auch von einem Internet-Café im Urlaub aus – vollen Zugriff auf alle archivierten E‐Mails hat. Heutzutage bieten die meisten E‐Mail-Anbieter sowohl einen POP3- als auch einen IMAP4-Zugang an. Im Vergleich zu POP3 unterstützt IMAP4 Kommandos zur komfortablen Verwaltung der Mails auf dem Server. So können beispielsweise Unterordner angelegt werden.

Im Gegensatz zu den bisherigen Protokollen wie FTP oder POP3 ist IMAP4 mit einem hohen Funktionsumfang ausgestattet, und obwohl das Protokoll immer noch auf lesbaren Textnachrichten basiert, ist es zu komplex, um es im Stil der bisherigen Abschnitte mit einer kurzen Tabelle ausreichend zu beschreiben.

Bei IMAP4 lassen sich E‐Mails in verschiedene Mailboxen einsortieren. Dabei können Sie sich eine Mailbox als ein Verzeichnis vorstellen, das E‐Mails enthalten kann, wie ein Ordner Dateien enthält. Die Mailbox-Struktur des verwendeten Beispielservers sieht folgendermaßen aus:

Mailbox-Struktur des Beispielservers

Abbildung 34.3    Mailbox-Struktur des Beispielservers

Es existieren eine übergeordnete Mailbox namens INBOX sowie zwei untergeordnete Mailboxen namens INBOX.Ham und INBOX.Spam.

IMAP4([host, port])

Um eine Verbindung zu einem IMAP4-Server herzustellen, muss eine Instanz der Klasse IMAP4 erzeugt werden. Der Konstruktor dieser Klasse kann direkt eine Verbindung zu einem IMAP4-Server mit dem Hostnamen host unter Verwendung des Ports port aufbauen. Wenn der Parameter port nicht angegeben wurde, wird der IMAP4-Standardport 143 verwendet.

Nachdem eine Instanz der Klasse IMAP4 erzeugt wurde, stellt diese verschiedene Methoden bereit, um mit dem verbundenen Server zu kommunizieren. Jede Methode, die ein IMAP4-Kommando repräsentiert, gibt ein Tupel der folgenden Form zurück:

(Status, [Daten, …])

Dabei steht im resultierenden Tupel für Status entweder "OK" oder "NO", je nachdem, ob die Operation erfolgreich verlaufen oder fehlgeschlagen ist. Das zweite Element des Tupels ist eine Liste der Daten, die der Server als Antwort geschickt hat. Diese Daten können entweder bytes-Strings oder Tupel sein. Wenn es sich um Tupel handelt, verfügen diese über jeweils zwei Elemente, beides bytes-Strings:

(Header, Daten)

Die Beispiele in den folgenden Abschnitten setzen zumeist eine verbundene IMAP4-Instanz im voraus:

>>> import imaplib
>>> im = imaplib.IMAP4("imap.server.de")

In den meisten Fällen muss die IMAP4-Instanz zudem beim Server eingeloggt sein, was im folgenden Abschnitt behandelt wird.

[»]  Hinweis

Die IMAP4-Klasse ist seit Python 3.5 ein Kontextmanager und lässt sich mit der with-Anweisung verwenden:

with imaplib.IMAP4("imap.server.de") as i:
pass

Eine Verbindung aufbauen und beenden

Sofern die IMAP4-Instanz im nicht bereits bei ihrer Erzeugung mit einem Server verbunden wurde, lässt sich dies über die Methode open nachholen. Diese verfügt ebenfalls über die Parameter host und port, analog zur Schnittstelle des IMAP4-Konstruktors.

Im zweiten Schritt wird die Methode login gerufen, um sich beim Server zu authentifizieren. Diese Methode bekommt den Benutzernamen und das Passwort als String übergeben. Eine bestehende Verbindung können Sie über die Methode logout beenden.

>>> im.login("Benutzername", "Passwort")
('OK', [b'Logged in'])
>>> im.logout()
('BYE', [b'Logging out'])

Eine Mailbox suchen und auswählen

Nach der Verbindung zu einem IMAP4-Server muss eine Mailbox ausgewählt werden, um an die darin enthaltenen E‐Mails zu gelangen. Die Methode list gibt die Namen aller Mailboxen zurück, die auf ein bestimmtes Pattern passen. Dazu bekommt sie den Basisordner übergeben, in dem gesucht werden soll, sowie das Pattern, auf das die Ergebnisse passen müssen. Das übergebene Pattern muss ein String sein und enthält üblicherweise Fragmente eines Mailbox-Namens inklusive Platzhalter *:

>>> im.list(".", "*Ham")
('OK', [b'(\\HasNoChildren) "." "INBOX.Ham"'])
>>> im.list(".", "*am")
('OK', [b'(\\HasNoChildren) "." "INBOX.Ham"',
b'(\\HasNoChildren) "." "INBOX.Spam"'])
>>> im.list(".", "*")
('OK', [b'(\\HasNoChildren) "." "INBOX.Ham"',
b'(\\HasNoChildren) "." "INBOX.Spam"',
b'(\\Unmarked \\HasChildren) "." "INBOX"'])
>>> im.list(".", "NichtVorhandeneMailbox")
('OK', [None])

Wenn kein Verzeichnis übergeben wird, werden Mailboxen des Hauptordners zurückgegeben. Geben Sie kein Pattern an, werden alle im jeweiligen Ordner enthaltenen Mailboxen zurückgegeben.

Jeder Eintrag der Ergebnisliste ist ein bytes-String und enthält drei jeweils durch ein Leerzeichen voneinander getrennte Informationen: die sogenannten Flags der Mailbox in Klammern, das Verzeichnis der Mailbox und den Mailbox-Namen, jeweils in doppelten Anführungsstrichen. Aus den Flags kann man beispielsweise die Information entnehmen, ob eine Mailbox untergeordnete Mailboxen enthält (\HasChildren) oder nicht (\HasNoChildren).

Nachdem eine passende Mailbox gefunden wurde, kann sie durch Aufruf der Methode select ausgewählt werden, um weitere Operationen auf ihr durchführen zu können. Dabei übergeben Sie als ersten Parameter den Namen der auszuwählenden Mailbox. Die Methode select gibt die Anzahl der E‐Mails zurück, die sich in der gewählten Mailbox befinden.

>>> im.select("INBOX")
('OK', [b'2'])

Es wird keine Exception geworfen, wenn die gewünschte Mailbox nicht existiert. Stattdessen muss der Fehler anhand des Rückgabewertes ausgemacht werden:

>>> im.select("INBOX.NichtExistent")
('NO', [b'Mailbox does not exist, or must be subscribed to.'])

Eine ausgewählte Mailbox kann über die Methode close geschlossen werden.

Operationen mit Mailboxen

Neben dem Auswählen und Schließen lassen sich weitere Operationen mit Mailboxen durchführen, die in Tabelle 34.11 kurz zusammengefasst werden. Jede dieser Operationen kann über eine entsprechende Methode einer verbundenen IMAP4-Instanz ausgeführt werden und bekommt einen oder mehrere Mailbox-Namen übergeben.

Methode Beschreibung
create(mailbox) Erstellt eine neue Mailbox namens mailbox.
delete(mailbox) Löscht die Mailbox mailbox.
rename(oldmailbox, newmailbox) Benennt die Mailbox oldmailbox in newmailbox um.

Tabelle 34.11    Operationen auf Mailboxen

E‐Mails suchen

Die Methode search sucht innerhalb der ausgewählten Mailbox nach E‐Mails, die auf ein oder mehrere angegebene Kriterien passen. Dazu hat die Methode die folgende Schnittstelle:

   search(charset, [*criteria])

Als Kriterium kann entweder der String "ALL" (alle Mails erfüllen dieses Kriterium) oder ein String des Formats "(FROM \"Johannes\")" verwendet werden. Das zweite Kriterium ist für alle Mails erfüllt, die von einem gewissen »Johannes« geschrieben wurden. Der Parameter charset spezifiziert das Encoding der Kriterium-Strings. Üblicherweise wird dieser Parameter nicht benötigt und None übergeben.

Die Methode search gibt die IDs der gefundenen E‐Mails in Form einer Liste zurück.

>>> im.search(None, '(FROM "Johannes")')
('OK', [b'1 2 3'])
>>> im.search(None, '(FROM "Johann")')
('OK', [b'1 2 3'])
>>> im.search(None, '(FROM "Johanninski")')
('OK', [b''])

E‐Mails abrufen

Zum Abrufen von E‐Mails existiert die Methode fetch mit der folgenden Schnittstelle:

fetch(message_set, message_parts)

Der Parameter message_set muss ein String sein, der die Mail-IDs der herunterzuladenden E‐Mails enthält. Dabei können diese entweder einzeln im String vorkommen ("1"), als Bereich ("1:4" für Mails Nr. 1 bis 4), als Liste von Bereichen ("1:4,7:9" für Mails Nr. 1 bis 4 und Nr. 7 bis 9) oder als Bereich mit unbestimmter oberer Grenze ("3:*" für alle Mails ab Mail Nr. 3).

Der zweite Parameter message_parts kennzeichnet, welche Teile der angegebenen E‐Mails heruntergeladen werden sollen. Ein Wert von "(RFC822)" bedeutet, die gesamte Mail, also inklusive des Mail-Headers, herunterzuladen. Bei einem Wert von "(BODY[TEXT])" wird nur der Text und bei "(BODY[HEADER])" nur der Header der E‐Mail heruntergeladen.

>>> im.fetch("1", "(BODY[TEXT])")
('OK', [(b'1 (BODY[TEXT] {29}',
b'Dies ist eine Testnachricht\r\n'), b')'])
>>> im.fetch("1:2", "(BODY[TEXT])")
('OK', [(b'1 (BODY[TEXT] {29}',
b'Dies ist eine Testnachricht\r\n'), b')',
(b'2 (BODY[TEXT] {25}',
b'Noch eine Testnachricht\r\n'), b')'])

Im Falle einer nicht vorhandenen Mail-ID wird keine Exception geworfen, sondern ein leeres Ergebnis zurückgegeben. Wenn die ID ungültig ist, kommt eine entsprechende Fehlermeldung zurück:

>>> im.fetch("100", "(BODY[TEXT])")
('OK', [None])
>>> im.fetch("KeineID", "(BODY[TEXT])")
('NO', [b'Error in IMAP command received by server.'])

Beispiel

Im folgenden Beispielprogramm wird das Modul imaplib dazu verwendet, zu einem IMAP4-Server zu verbinden und alle enthaltenen E‐Mails einer bestimmten Mailbox anzuzeigen. Dabei erhält der Benutzer die Möglichkeit, die Mailbox zu wählen. Der Quelltext des Beispielprogramms sieht folgendermaßen aus:

import imaplib
im = imaplib.IMAP4("imap.server.de")
im.login("Benutzername", "Passwort")
print("Vorhandene Mailboxen:")
for mb in im.list()[1]:
name = mb.split(b'"."')[-1]
print(" - {}".format(name.decode().strip(' "')))
mb = input("Welche Mailbox soll angezeigt werden: ")
im.select(mb)
status, daten = im.search(None, "ALL")
for mailnr in daten[0].split():
typ, daten = im.fetch(mailnr, "(RFC822)")
print("{}\n+++\n".format(daten[0][1].decode()))
im.close()
im.logout()

Zunächst wird eine Instanz der Klasse IMAP4 erzeugt und zu einem IMAP4-Server verbunden. Dann werden mithilfe der Methode list alle im Hauptordner des IMAP4-Kontos vorhandenen Mailboxen durchlaufen und die Namen der Mailboxen auf dem Bildschirm angezeigt. Beachten Sie dabei, dass die Methode list die Namen der Mailboxen mit zusätzlichen Informationen zurückgibt. Diese Informationen müssen herausgefiltert werden, bevor der Mailbox-Name angezeigt werden kann. Nachdem die Namen angezeigt wurden, wird der Benutzer dazu aufgefordert, einen der angegebenen Mailbox-Namen auszuwählen.

Die vom Benutzer ausgewählte Mailbox wird dann mithilfe der Methode select auch auf dem Server ausgewählt. Der danach aufgerufenen Methode search übergeben wir den String "ALL", was den Mail-Server dazu veranlasst, Daten über alle E‐Mails der ausgewählten Mailbox zurückzugeben.

Anschließend iterieren wir in einer for-Schleife über die Liste von Mail-IDs, die search zurückgegeben hat, und laden die jeweilige Mail mit fetch vollständig herunter. Die heruntergeladene Mail wird auf dem Bildschirm ausgegeben.

Zuletzt schließen wir die ausgewählte Mailbox und beenden die Verbindung mit dem Server.

Auch bei diesem Beispielprogramm wurde keine Fehlerbehandlung durchgeführt. In einem fertigen Programm sollten sowohl die Verbindungsanfrage als auch das Login und insbesondere die Benutzereingabe überprüft werden.

 
Zum Seitenanfang

34.4.4    Erstellen komplexer E‐Mails – email Zur vorigen ÜberschriftZur nächsten Überschrift

In den vorangegangenen Abschnitten haben Sie erfahren, wie Sie E‐Mails über einen SMTP-Server versenden und von einem POP3- oder IMAP4-Server herunterladen. Wie Sie wissen, basiert das Senden und Empfangen von E‐Mails auf reinen ASCII-Protokollen. Das bedeutet vor allem, dass mit diesen Protokollen keine Binärdaten verschickt werden können. Außerdem sind Sonderzeichen, die nicht dem 7-Bit-ASCII-Standard entsprechen, problematisch.

Um solche Zeichen oder Binärdaten verschicken zu können, wurde der MIME-Standard[ 151 ](Multipurpose Internet Mail Extension) entwickelt, der Sonderzeichen und Binärdaten so codiert, dass sie als eine Folge reiner ASCII-Zeichen versandt werden können. Zudem definiert der MIME-Standard verschiedene Dateitypen und legt eine Syntax fest, mit der Dateianhänge einem bestimmten Dateityp zugeordnet werden, sodass die Dateien beim Empfänger leichter verarbeitet werden können.

Das zugehörige Paket email ist sehr mächtig, weswegen hier nur ein Teil seines Funktionsumfangs besprochen werden kann. Zunächst werden wir uns darum kümmern, wie eine einfache ASCII-Mail mittels email erstellt werden kann. Darauf aufbauend werden wir zu komplexeren MIME-codierten Mails übergehen.

Erstellen einer einfachen E‐Mail

Als Basisklasse für eine neue E‐Mail dient die Klasse Message des Moduls email. message. Das folgende Beispielprogramm zeigt, wie sie verwendet wird:

from email.message import Message
msg = Message()
msg.set_payload("Dies ist meine selbst erstellte E‐Mail.")
msg["Subject"] = "Hallo Welt"
msg["From"] = "Donald Duck <don@ld.de>"
msg["To"] = "Onkel Dagobert <d@gobert.de>"
print(msg.as_string())

Die Ausgabe des Beispielprogramms, also die erzeugte E‐Mail, sieht folgendermaßen aus:

Subject: Hallo Welt
From: Donald Duck <don@ld.de>
To: Onkel Dagobert <d@gobert.de>

Dies ist meine selbst erstellte E‐Mail.

Zunächst erzeugen wir eine Instanz der Klasse Message. Der Konstruktor dieser Klasse erwartet keine Argumente. Durch die Methode set_payload (dt. »Nutzlast«) wird der E‐Mail ein Text hinzugefügt.

Jetzt fehlt nur noch der E‐Mail-Header. Um diesen hinzuzufügen, kann die Message-Instanz wie ein Dictionary angesprochen werden. Auf diese Weise werden die einzelnen Teile des Headers hinzugefügt. Wichtig sind dabei "Subject" für den Betreff, "From" für den Absender und "To" für den Empfänger der Mail.

Zu guter Letzt wird die entstandene E‐Mail durch die Methode as_string in einen String geschrieben und ausgegeben.[ 152 ](Mithilfe des Moduls smtplib kann der erzeugte E‐Mail-String oder die Message-Instanz direkt verschickt werden. )

Erstellen einer E‐Mail mit Anhängen

Wir haben angekündigt, dass es das Paket email ermöglicht, Binärdaten per E‐Mail zu verschicken. Dafür ist das Modul email.mime zuständig. Das folgende Beispielprogramm erstellt eine E‐Mail und fügt eine Bilddatei als Anhang ein:

from email.mime.multipart import MIMEMultipart
from email.mime.image import MIMEImage
from email.mime.text import MIMEText
msg = MIMEMultipart()
msg["Subject"] = "Hallo Welt"
msg["From"] = "Donald Duck <don@ld.de>"
msg["To"] = "Onkel Dagobert <d@gobert.de>"
text = MIMEText("Dies ist meine selbst erstellte E‐Mail.")
msg.attach(text)
f = open("lena.png", "rb")
bild = MIMEImage(f.read())
f.close()
msg.attach(bild)
print(msg.as_string())

Zunächst wird eine Instanz der Klasse MIMEMultipart erzeugt. Diese repräsentiert eine E‐Mail, die MIME-codierte Binärdaten enthalten kann. Wie im vorangegangenen Beispiel werden Betreff, Absender und Empfänger nach Art eines Dictionarys hinzugefügt.

Danach wird eine Instanz der Klasse MIMEText erzeugt, die den reinen Text der E‐Mail enthalten soll. Diese Instanz wird mithilfe der Methode attach an die MIMEMultipart-Instanz angehängt.

Genauso verfahren wir mit dem Bild: Es wird eine Instanz der Klasse MIMEImage erzeugt und mit den Binärdaten des Bildes gefüllt. Danach wird sie mittels attach an die E‐Mail angefügt.

Schließlich wird die MIMEMultipart-Instanz durch Aufruf der Methode as_string in einen String konvertiert, der so als reine ASCII-E‐Mail versendet werden kann. Der angefügte Anhang wird von E‐Mail-Programmen als Grafik erkannt und dann dementsprechend präsentiert. Die Ausgabe des Beispiels sieht so aus:

Content-Type: multipart/mixed; boundary="===========0094312333=="
MIME-Version: 1.0
Subject: Hallo Welt
From: Donald Duck <don@ld.de>
To: Onkel Dagobert <d@gobert.de>

--===============0094312333==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit

Dies ist meine selbst erstellte E‐Mail.
--===============0094312333==
Content-Type: image/png
MIME-Version: 1.0
Content-Transfer-Encoding: base64

iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAIAAAAiOjnJAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAg
AElEQVR4nIS8Sa9tXXYsFBFjzrXPucVXZWlnukC200bvGR6FEeJ1wAghJPgxgOjSR+JPICHRgA4N
[…]
--===============0094312333==--

Sie sehen, dass sowohl der Text als auch das Bild in ähnlicher Form codiert wurden. Die Aufbereitung der beiden Sektionen zum Textteil der E‐Mail und zu einem Bild im Anhang erledigt Ihr Mail-Programm. Das mime-Paket bietet auch eine entsprechende Funktionalität an, auf die wir noch zu sprechen kommen werden.

Tabelle 34.12 listet die verfügbaren MIME-Datentypen auf:

MIME-Datentyp Zweck
email.mime.application.MIMEApplication Programme
email.mime.audio.MIMEAudio Audiodateien
email.mime.image.MIMEImage Grafikdateien
email.mime.message.MIMEMessage Message-Instanzen
email.mime.image.MIMEText reiner Text

Tabelle 34.12    Verfügbare MIME-Datentypen

Beim Instanziieren all dieser Klassen müssen Sie die jeweiligen Binärdaten bzw. den Text, den die entsprechende Instanz enthalten soll, als ersten Parameter des Konstruktors übergeben. Wichtig ist noch, dass alle hier vorgestellten Klassen von der Basisklasse Message abgeleitet sind, also über die Methoden dieser Basisklasse verfügen.

Internationale Zeichensätze

Bisher wurde besprochen, wie der MIME-Standard dazu verwendet werden kann, Binärdaten im Anhang einer E‐Mail zu versenden. Beim Text der E‐Mail waren wir aber bislang auf die Zeichen des 7-Bit-ASCII-Standards beschränkt. Die Frage ist, wie ein spezielles Encoding innerhalb einer E‐Mail verwendet werden kann. Auch dies ermöglicht der MIME-Standard. Das folgende Beispielprogramm erstellt eine einfache E‐Mail, deren Text ein Eurozeichen enthält:

from email.mime.text import MIMEText
text = "39,90\u20AC"
msg = MIMEText(text.encode("cp1252"), _charset="cp1251")
msg["Subject"] = "Hallo Welt"
msg["From"] = "Donald Duck <don@ld.de>"
msg["To"] = "Onkel Dagobert <d@gobert.de>"
print(msg.as_string())

Als Erstes erzeugen wir einen String, der das Eurozeichen enthält, das nicht Teil des ASCII-Standards ist. Im Folgenden wird der String ins Windows-Encoding cp1252 codiert und bei der Instanziierung der Klasse MIMEText übergeben. Das verwendete Encoding muss dem Konstruktor ebenfalls über den Parameter _charset bekannt gemacht werden. Der nun folgende Teil des Programms ist Ihnen bereits von den anderen Beispielen her bekannt.

Der MIME-codierte Text, den das Beispielprogramm ausgibt, sieht folgendermaßen aus:

Content-Type: text/plain; charset="cp1252"
MIME-Version: 1.0
Content-Transfer-Encoding: base64
Subject: Hallo Welt
From: Donald Duck <don@ld.de>
To: Onkel Dagobert <d@gobert.de>

MzksOTCA

Dabei entspricht MzksOTCA der MIME-Codierung des Textes 39,90€.

Es kann durchaus vorkommen, dass auch Einträge im Header der E‐Mail Sonderzeichen enthalten. Sie können mithilfe der Klasse Header codiert werden:

from email.mime.text import MIMEText
from email.header import Header
msg = MIMEText("Hallo Welt")
msg["Subject"] = Header("39,90\u20AC", "cp1252")
[…]

Eine E‐Mail einlesen

Zum Schluss möchten wir Ihnen noch ein kurzes Beispiel dazu geben, dass eine abgespeicherte E‐Mail auch wieder eingelesen und automatisch zu der bislang besprochenen Klassenstruktur aufbereitet werden kann. Dazu folgendes Beispiel:

import email
mail = """Subject: Hallo Welt
From: Donald Duck <don@ld.de>
To: Onkel Dagobert <d@gobert.de>

Hallo Welt

"""
msg = email.message_from_string(mail)
print(msg["From"])

Im Beispielprogramm ist eine E‐Mail in Form eines Strings vorhanden und wird durch die Funktion message_from_string eingelesen. Diese Funktion gibt eine Message-Instanz zurück, wie die darauffolgende print-Ausgabe beweist:

Donald Duck <don@ld.de>

Alternativ hätten wir auch die Funktion message_from_file verwenden können, um die E‐Mail aus einer Datei zu lesen. Dieser Funktion hätten wir dann ein geöffnetes Dateiobjekt übergeben müssen.

 


Ihre Meinung

Wie hat Ihnen das Openbook gefallen? Wir freuen uns immer über Ihre Rückmeldung. Schreiben Sie uns gerne Ihr Feedback als E-Mail an kommunikation@rheinwerk-verlag.de.

<< zurück
 Zum Rheinwerk-Shop
Zum Rheinwerk-Shop: Python 3 Python 3
Jetzt Buch bestellen

 Buchempfehlungen
Zum Rheinwerk-Shop: Einstieg in Python
Einstieg in Python


Zum Rheinwerk-Shop: Python. Der Grundkurs
Python. Der Grundkurs


Zum Rheinwerk-Shop: Algorithmen mit Python
Algorithmen mit Python


Zum Rheinwerk-Shop: Objektorientierte Programmierung
Objektorientierte Programmierung


Zum Rheinwerk-Shop: Raspberry Pi. Das umfassende Handbuch
Raspberry Pi. Das umfassende Handbuch


Zum Rheinwerk-Shop: Roboter-Autos mit dem Raspberry Pi
Roboter-Autos mit dem Raspberry Pi


Zum Rheinwerk-Shop: Neuronale Netze programmieren mit Python
Neuronale Netze programmieren mit Python


 Lieferung
Versandkostenfrei bestellen in Deutschland, Österreich und der Schweiz
InfoInfo

 
 


Copyright © Rheinwerk Verlag GmbH 2020
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das Openbook denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt.
Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.

 
[Rheinwerk Computing]

Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de

Cookie-Einstellungen ändern