适用于 Python 的邮件 API

本页面介绍如何将 Mail API(一种旧版捆绑服务)与标准环境中的 Python 运行时搭配使用。您的应用可以通过 Python 版 App Engine 服务 SDK 访问捆绑服务。

概览

在 Python 中,邮件处理功能包含在 google.appengine.api.mail 模块中。这与 Python 2 不同,在 Python 2 中,mail_handlers 模块由 webapp 提供。适用于 Python 的邮件 API 可用于接收电子邮件和退信通知。

使用邮件 API

当电子邮件作为 HTTP POST 请求中的请求正文发送时,您的应用会收到邮件。为了让应用处理传入的电子邮件,应用需要将网址与路径 /_ah/mail/[ADDRESS] 进行匹配。路径的 [ADDRESS] 部分通常是带有后缀 @<Cloud-Project-ID>.appspotmail.com 的电子邮件地址。以此格式发送到应用的电子邮件将路由到函数。

Python 不需要应用在 app.yaml 文件中指定处理程序脚本,因此您可以移除 app.yaml 中的所有 handler 部分。

您的 app.yaml 文件应保留以下行:

inbound_services:
- mail
- mail_bounce

发送邮件

升级到 Python 时,您无需更改应用的配置。用于发送邮件的行为、功能和设置说明保持不变。如需了解详情,请参阅以下指南:

接收邮件

要接收邮件,您需要导入 google.appengine.api.mail 模块并使用 InboundEmailMessage 类来表示电子邮件。该类需要实例化才能从传入的 HTTP 请求中检索电子邮件内容。

以前,在 Python 2 中,应用可以通过替换 webapp 处理程序 InboundEmailHandler 中的 receive() 方法来访问 InboundEmailMessage 类。在 Python 中不需要如此操作;相反,应用需要实例化新对象。

Web 框架

使用 Python 网络框架时,InboundEmailMessage 构造函数会接收 HTTP 请求正文的字节。您可以使用多种方法在 Python 中创建 InboundEmailMessage 对象。以下是 Flask 和 Djago 应用的示例:

Python 3 (Flask)

在 Flask 中,request.get_data() 提供请求字节数。

@app.route("/_ah/mail/<path>", methods=["POST"])
def receive_mail(path):
    message = mail.InboundEmailMessage(request.get_data())

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

    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 兼容的框架,我们建议使用与 Flask 和 Django 示例相同的方法来创建 InboundEmailMessage。当 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}", [])