Python 用 Mail API

このページでは、以前のバンドル サービスの一つである Mail API を、スタンダード環境の Python ランタイムとともに使用する方法を説明します。アプリを使用すると Python 用 App Engine サービス SDK を介してバンドル サービスにアクセスできます。

概要

Python では、メール処理機能は google.appengine.api.mail モジュールに含まれています。これは、mail_handlers モジュールが webapp によって提供される Python 2 とは異なります。Python 用 Mail API を使用すると、メールとバウンス通知を受信できます。

Mail API の使用

HTTP POST リクエストでリクエスト本文としてメールが送信されると、アプリはメールを受信します。アプリが受信メールを処理できるように、URL とパス /_ah/mail/[ADDRESS] を一致させる必要があります。通常、パスの [ADDRESS] 部分は、@<Cloud-Project-ID>.appspotmail.com というサフィックスが付いたメールアドレスになります。この形式でアプリに送信されたメールは、関数に転送されます。

Python では、アプリで app.yaml ファイルのハンドラ スクリプトを指定する必要がないため、app.yamlhandler セクションはすべて削除できます。

次の行は、app.yaml ファイルに含まれている必要があります。

inbound_services:
- mail
- mail_bounce

メールの送信

Python にアップグレードする際に、アプリの構成を変更する必要はありません。メール送信の動作、機能、設定手順は、以前と同じです。詳細については、次のガイドをご覧ください。

メールの受信

メールを受信するには、google.appengine.api.mail モジュールをインポートし、InboundEmailMessage クラスを使用してメールを表現する必要があります。このクラスは、受信 HTTP リクエストからメール コンテンツを取得するためにインスタンス化する必要があります。

以前の Python 2 では、webapp ハンドラ InboundEmailHandlerreceive() メソッドをオーバーライドすることで、InboundEmailMessage クラスにアクセスできました。Python では、その必要はありませんが、アプリで新しいオブジェクトをインスタンス化する必要があります。

ウェブ フレームワーク

Python ウェブ フレームワークを使用する際は、InboundEmailMessage コンストラクタが HTTP リクエスト本文のバイト列を取り込みます。Python では、InboundEmailMessage オブジェクトを作成する方法が複数あります。次に Flask アプリと Djago アプリの例を示します。

Python 3(Flask)

Flask では、request.get_data() によってリクエスト バイト列が与えられます。

@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)

Django では、request.body によって HTTP リクエスト本文のバイト列が与えられます。

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")

このガイドの完全なコードサンプルについては、GitHub をご覧ください。

他の WSGI 準拠のフレームワーク

他の WSGI 準拠のフレームワークでは、InboundEmailMessage の作成に Flask や Django の例と同じ方法を使用することをおすすめします。この方法は、HTTP リクエスト本文のバイト列を直接利用できる場合に機能します。

ウェブ フレームワークを使用しない WSGI アプリ

ウェブ フレームワークを使用しない WSGI アプリの場合は、HTTP リクエスト本文のバイト列を直接利用できない可能性があります。HTTP リクエスト本文のバイト列を直接利用できる場合は、Python のウェブ フレームワークを使用することをおすすめします。

Python では、InboundEmailMessage 用に、from_environ という Factory メソッドが定義されています。このメソッドは、WSGI environ ディクショナリを入力として使用するクラスメソッドで、どの WSGI アプリケーションでも使用できます。

次の例では、environ を入力として受け取り、mail_message を取得する方法を示しています。

Python 3(WSGI アプリ)

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")]

バウンス通知の受信

バウンス通知とは、メールシステムから自動的に送信されるメッセージの一つで、アプリのメッセージ配信に問題があることを示すものです。バウンス通知を処理するには、受信 URL パスと /_ah/bounce パスを一致させる必要があります。

Python 2 では、InboundEmailMessage と同様、webapp ハンドラ BounceNotificationHandlerreceive() メソッドをオーバーライドすることで BounceNotification クラスにアクセスできました。

Python では、アプリで BounceNotification オブジェクトをインスタンス化する必要があります。このオブジェクトは、使用する Python ウェブ フレームワークに応じて、複数の方法で作成できます。

ウェブ フレームワーク

BounceNotification オブジェクトは、post_vars.get(key) を呼び出して取得する値で初期化されます。

Python のウェブ フレームワーク(Flask や Django など)を使用する場合、BounceNotification コンストラクタは、フォームデータの POST リクエストが含まれている post_vars という名前のディクショナリ受け取ります。そのデータを取得するには、入力オブジェクトでメソッド get() を定義する必要があります。key は、BounceNotification で読み書き可能な入力値のリストで、次のいずれかになります。

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

ほとんどのウェブ フレームワークでは、このデータはリクエスト オブジェクトのマルチ ディクショナリとして使用できます。これらの型のほとんどは、文字列をキーとするディクショナリに変換できます。

raw-message を除くすべてのキーについて、値は自由に設定できます。通常、値は文字列などの単一の値か、{'to': ['bob@example.com', 'alice@example.com']} などの値のリストになります。すべてのフィールドのデフォルト値は空の文字列です。これらの値は、original プロパティと notification プロパティに入力されます。

raw-message キーの場合、値は EmailMessage のコンストラクタへの有効な入力である必要があります。値は 1 つでも、値のリストでも構いません。raw-message キーは、オブジェクトの original_raw_message プロパティを初期化するために使用されます。

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)

Flask では、werkzeug.datastructures.MultiDict 型の request.form によって POST 変数が与えられます。ただし、この型の get() メソッドは、キーに複数の値が存在する場合でも、1 つの値のみを返します。

キーに対応するすべての値を取得するには、アプリで dict(request.form.lists()) を呼び出す必要があります。これにより、各値がリストになっているディクショナリが作成されます。

@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)

Django では、django.http.QueryDict 型の request.POST によって POST 変数が与えられます。ただし、この型の get() メソッドは、キーに複数の値が存在する場合でも、1 つの値のみを返します。

キーに対応するすべての値を取得するには、アプリで dict(request.POST.lists()) を呼び出す必要があります。これにより、各値がリストになっているディクショナリが作成されます。

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 アプリ

アプリがウェブ フレームワークを使用しない WSGI アプリの場合は、ディクショナリで HTTP POST リクエストのフォーム変数が直接使用できない可能性があります。

Python では、BounceNotification 用に、from_environ という Factory メソッドが定義されています。このメソッドは、WSGI environ ディクショナリを入力として使用するクラスメソッドで、どの WSGI アプリケーションでも使用できます。

次の例では、environ を入力として受け取り、bounce_message を取得する方法を示しています。

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")]

コードサンプル

このガイドの完全なコードサンプルについては、GitHub をご覧ください。