Mail API für Python

Auf dieser Seite wird beschrieben, wie Sie die Mail API, einen der gebündelten Legacy-Dienste, mit der Python-Laufzeit für die Standardumgebung verwenden. Ihre Anwendung kann über das App Engine Services SDK für Python auf die gebündelten Dienste zugreifen.

Überblick

In Python ist die E-Mail-Verarbeitungsfunktion im Modul google.appengine.api.mail enthalten. Dies unterscheidet sich von Python 2, wo das Modul mail_handlers von webapp bereitgestellt wurde. Mit der Mail API für Python können Sie E-Mails und Rücksendebenachrichtigungen empfangen.

Mail API verwenden

Ihre Anwendung empfängt E-Mails, wenn eine E-Mail als Anfragetext in einer HTTP-POST-Anfrage gesendet wird. Damit die Anwendung eingehende E-Mails verarbeiten kann, muss sie mit der URL mit dem Pfad /_ah/mail/[ADDRESS] übereinstimmen. Der Teil [ADDRESS] des Pfads ist normalerweise eine E-Mail-Adresse mit dem Suffix @<Cloud-Project-ID>.appspotmail.com. E-Mails, die in diesem Format an die Anwendung gesendet werden, werden an die Funktion weitergeleitet.

Für Python muss die Anwendung kein Handler-Skript in der Datei app.yaml angeben. Deshalb können Sie alle handler-Abschnitte in app.yaml entfernen.

Die Datei app.yaml sollte die folgenden Zeilen enthalten:

inbound_services:
- mail
- mail_bounce

E-Mails senden

Sie müssen keine Änderungen an der Konfiguration Ihrer Anwendung vornehmen, wenn Sie ein Upgrade auf Python machen. Das Verhalten, die Funktionen und die Einrichtungsanleitung für das Senden von E-Mails bleiben gleich. Ausführliche Informationen finden Sie in den folgenden Leitfäden:

E-Mails empfangen

Zum Empfangen von E-Mails müssen Sie das Modul google.appengine.api.mail importieren und die Klasse InboundEmailMessage verwenden, um eine E-Mail-Adresse darzustellen. Diese Klasse muss instanziiert werden, um den E-Mail-Inhalt aus der eingehenden HTTP-Anfrage abzurufen.

Bisher konnten Anwendungen in Python 2 auf die Klasse InboundEmailMessage zugreifen. Dazu wurde die Methode receive() im webapp-Handler InboundEmailHandler überschrieben. Dies ist in Python nicht erforderlich. Stattdessen muss die Anwendung ein neues Objekt instanziieren.

Web-Frameworks

Wenn Sie Python-Web-Frameworks verwenden, übernimmt der Konstruktor InboundEmailMessage die Byte des HTTP-Anfragetexts. Es gibt mehrere Möglichkeiten, das Objekt InboundEmailMessage in Python zu erstellen. Im Folgenden finden Sie Beispiele für die Anwendungen Flask und Djago:

Python 3 (Flask)

In Flask gibt request.get_data() die Anfragebyte an.

@app.route("/_ah/bounce", methods=["POST"])
def receive_bounce():
    bounce_message = mail.BounceNotification(dict(request.form.lists()))

    # Do something with the message
    print("Bounce original: ", bounce_message.original)
    print("Bounce notification: ", bounce_message.notification)

    return "OK", 200

Python 3 (Django)

In Django gibt request.body die Bytes des HTTP-Anfragetexts an.

def receive_mail(request):
    message = mail.InboundEmailMessage(request.body)

    print(f"Received greeting for {message.to} at {message.date} from {message.sender}")
    for _, payload in message.bodies("text/plain"):
        print(f"Text/plain body: {payload.decode()}")
        break

    return HttpResponse("OK")

Die vollständigen Codebeispiele aus dieser Anleitung finden Sie unter GitHub.

Andere WSGI-kompatible Frameworks

Für andere WSGI-kompatible Frameworks wird empfohlen, die gleiche Methode wie in den Flask- und Django-Beispielen zu verwenden, um die InboundEmailMessage zu erstellen. Diese Methode funktioniert, wenn die Byte des HTTP-Anfragetexts direkt verfügbar sind.

WSGI-Anwendung ohne Web-Framework

Wenn Ihre Anwendung eine WSGI-Anwendung ist, die kein Web-Framework verwendet, sind die Byte des HTTP-Anfragetexts möglicherweise nicht direkt verfügbar. Wenn die Byte des HTTP-Anfragetexts direkt verfügbar sind, empfehlen wir die Verwendung eines Python-Web-Frameworks.

In Python ist für InboundEmailMessage eine Factory-Methode mit dem Namen from_environ definiert. Diese Methode ist eine Klassenmethode, die das WSGI-Dictionary environ als Eingabe verwendet und für jede WSGI-Anwendung verwendet werden kann.

Im folgenden Beispiel ist zu sehen, wie environ als Eingabe verwendet wird, um die mail_message zu erhalten:

Python 3 (WSGI-Anwendung)

def HelloReceiver(environ, start_response):
    if environ["REQUEST_METHOD"] != "POST":
        return ("", http.HTTPStatus.METHOD_NOT_ALLOWED, [("Allow", "POST")])

    message = mail.InboundEmailMessage.from_environ(environ)

    print(f"Received greeting for {message.to} at {message.date} from {message.sender}")
    for content_type, payload in message.bodies("text/plain"):
        print(f"Text/plain body: {payload.decode()}")
        break

    response = http.HTTPStatus.OK
    start_response(f"{response.value} {response.phrase}", [])
    return ["success".encode("utf-8")]

Unzustellbarkeitsnachricht erhalten

Eine Unzustellbarkeitsnachricht ist eine automatische Nachricht eines E-Mail-Systems, die auf ein Problem mit der Nachrichtenzustellung Ihrer Anwendung hinweist. Damit Unzustellbarkeitsnachrichten verarbeitet werden können, muss Ihre Anwendung eingehende URL-Pfade mit dem Pfad /_ah/bounce abgleichen.

Wie InboundEmailMessage war auch die Klasse BounceNotification für Python 2 durch Überschreiben der Methode receive() im Webapp-Handler BounceNotificationHandler zugänglich.

In Python muss die Anwendung das Objekt BounceNotification instanziieren, das je nach verwendetem Python-Web-Framework auf verschiedene Arten erstellt werden kann.

Web-Frameworks

Das Objekt BounceNotification wird mit den Werten initialisiert, die durch Aufrufen von post_vars.get(key) abgerufen werden.

Wenn Sie ein Python-Web-Framework wie Flask oder Django verwenden, übernimmt der Konstruktor BounceNotification ein Dictionary namens post_vars, das die POST-Anfrage der Formulardaten enthält. Zum Abrufen der Daten muss die Methode get() für das Eingabeobjekt definiert werden. Der key ist eine Liste von Eingabewerten, die von BounceNotification gelesen und abgerufen werden können und folgende Werte sein können:

original-to, original-cc, original-bcc, original-subject, original-text, notification-from, notification-to, notification-cc, notification-bcc, notification-subject, notification-text, raw-message

In den meisten Web-Frameworks sind diese Daten als Multi-Dictionary im Anfrageobjekt verfügbar. Die meisten dieser Typen können in ein Dictionary umgewandelt werden, das aus Strings besteht.

Bei allen Schlüsseln außer raw-message kann der Wert beliebig sein. Normalerweise ist der Wert entweder ein einzelner Wert wie ein String oder eine Liste von Werten wie {'to': ['bob@example.com', 'alice@example.com']}. Der Standardwert für alle Felder ist ein leerer String. Diese Werte füllen die Attribute original und notification aus.

Für den Schlüssel raw-message muss der Wert eine gültige Eingabe für den Konstruktor von EmailMessage sein. Es kann sich entweder um einen einzelnen Wert oder eine Liste mit einem einzelnen Wert handeln. Der Schlüssel raw-message wird verwendet, um das Attribut original_raw_message des Objekts zu initialisieren.

Python 2 (webapp2)

class LogBounceHandler(BounceNotificationHandler):
    def receive(self, bounce_message):
        logging.info('Received bounce post ... [%s]', self.request)
        logging.info('Bounce original: %s', bounce_message.original)
        logging.info('Bounce notification: %s', bounce_message.notification)

Python 3 (Flask)

In Flask stellt request.form vom Typ werkzeug.datastructures.MultiDict die POST-Variablen bereit. Die Methode get() gibt für diesen Typ jedoch nur dann einen Wert zurück, wenn mehrere Werte für den Schlüssel vorhanden sind.

Um alle Werte abzurufen, die einem Schlüssel entsprechen, muss die Anwendung dict(request.form.lists()) aufrufen. Dies führt zu einem Dictionary, in dem jeder Wert eine Liste ist.

@app.route("/_ah/bounce", methods=["POST"])
def receive_bounce():
    bounce_message = mail.BounceNotification(dict(request.form.lists()))

    # Do something with the message
    print("Bounce original: ", bounce_message.original)
    print("Bounce notification: ", bounce_message.notification)

    return "OK", 200

Python 3 (Django)

In Django stellt request.POST vom Typ django.http.QueryDict die POST-Variablen bereit. Die Methode get() gibt für diesen Typ jedoch nur dann einen Wert zurück, wenn mehrere Werte für den Schlüssel vorhanden sind.

Um alle Werte abzurufen, die einem Schlüssel entsprechen, muss die Anwendung dict(request.POST.lists()) aufrufen. Dies führt zu einem Dictionary, in dem jeder Wert eine Liste ist.

def receive_bounce(request):
    bounce_message = mail.BounceNotification(dict(request.POST.lists()))

    # Do something with the message
    print(f"Bounce original: {bounce_message.original}")
    print(f"Bounce notification: {bounce_message.notification}")

    return HttpResponse("OK")

WSGI-Anwendung ohne Web-Framework

Wenn Ihre Anwendung eine WSGI-Anwendung ist, die kein Web-Framework verwendet, sind die Formularvariablen der HTTP-POST-Anfrage möglicherweise nicht direkt in einem Wörterbuch verfügbar.

In Python ist für BounceNotification eine Factory-Methode mit dem Namen from_environ definiert. Diese Methode ist eine Klassenmethode, die das WSGI-Wörterbuch environ als Eingabe verwendet und für jede WSGI-Anwendung verwendet werden kann.

Im folgenden Beispiel ist zu sehen, wie environ als Eingabe verwendet wird, um die bounce_message zu erhalten:

Python 3

def BounceReceiver(environ, start_response):
    if environ["REQUEST_METHOD"] != "POST":
        return ("", http.HTTPStatus.METHOD_NOT_ALLOWED, [("Allow", "POST")])

    bounce_message = mail.BounceNotification.from_environ(environ)

    # Do something with the message
    print("Bounce original: ", bounce_message.original)
    print("Bounce notification: ", bounce_message.notification)

    # Return suitable response
    response = http.HTTPStatus.OK
    start_response(f"{response.value} {response.phrase}", [])
    return ["success".encode("utf-8")]

Codebeispiele

Die vollständigen Codebeispiele aus dieser Anleitung finden Sie unter GitHub.