Python 3용 Mail API

이 페이지에서는 표준 환경의 Python 3 런타임에서 기존 번들 서비스 중 하나인 Mail API를 사용하는 방법을 설명합니다. 앱은 Python 3용 App Engine 서비스 SDK를 통해 번들 서비스에 액세스할 수 있습니다.

개요

Python 3에서는 메일 처리 기능이 google.appengine.api.mail 모듈에 포함되어 있습니다. 이는 웹 앱에서 mail_handlers 모듈을 제공한 Python 2와 다릅니다. Python 3용 Mail API를 사용하여 이메일과 반송 알림을 받을 수 있습니다.

Mail API 사용

이메일이 HTTP POST 요청의 요청 본문으로 전송되면 앱에서 메일을 수신합니다. 앱에서 수신 이메일을 처리하려면 URL을 /_ah/mail/[ADDRESS] 경로와 일치시켜야 합니다. 경로의 [ADDRESS] 부분은 일반적으로 서픽스 @<Cloud-Project-ID>.appspotmail.com이 있는 이메일 주소입니다. 이 형식으로 앱에 전송된 이메일은 함수로 라우팅됩니다.

Python 3에서는 앱이 app.yaml 파일에 핸들러 스크립트를 지정할 필요가 없으므로 app.yaml의 모든 handler 섹션을 삭제할 수 있습니다.

app.yaml 파일은 다음 줄을 보관해야 합니다.

inbound_services:
- mail
- mail_bounce

메일 보내기

Python 3으로 업그레이드할 때 앱 구성을 변경할 필요가 없습니다. 메일 전송의 동작, 기능, 설정 안내는 동일하게 유지됩니다. 자세한 내용은 다음 가이드를 참조하세요.

메일 받기

메일을 수신하려면 google.appengine.api.mail 모듈을 가져오고 InboundEmailMessage 클래스를 사용하여 이메일을 나타내야 합니다. 이 클래스는 수신되는 HTTP 요청에서 이메일 콘텐츠를 검색하도록 인스턴스화되어야 합니다.

이전 Python 2에서는 웹 앱 핸들러 InboundEmailHandler에서 receive() 메서드를 재정의하여 앱이 InboundEmailMessage 클래스에 액세스할 수 있었습니다. Python 3에서는 이렇게 할 필요가 없습니다. 대신 앱에서 새 객체를 인스턴스화해야 합니다.

웹 프레임워크

Python 웹 프레임워크를 사용하는 경우 InboundEmailMessage 생성자는 HTTP 요청 본문의 바이트를 사용합니다. Python 3에서 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 준수 프레임워크의 경우 Flask 및 Django 예시와 동일한 메서드를 사용하여 InboundEmailMessage를 만드는 것이 좋습니다. 이 메서드는 HTTP 요청 본문의 바이트를 직접 사용할 수 있는 경우에 작동합니다.

웹 프레임워크가 없는 WSGI 앱

앱이 웹 프레임워크를 사용하지 않는 WSGI 앱인 경우 HTTP 요청 본문의 바이트를 직접 사용할 수 없습니다. HTTP 요청 본문의 바이트를 직접 사용할 수 있으면 Python 웹 프레임워크를 사용하는 것이 좋습니다.

Python 3에서는 from_environ이라는 팩토리 메서드가 InboundEmailMessage에 정의되어 있습니다. 이 메서드는 WSGI environ 사전을 입력으로 사용하는 클래스 메서드이며 모든 WSGI 애플리케이션에 사용될 수 있습니다.

다음 예시에서는 mail_message를 가져오기 위해 environ이 입력으로 어떻게 사용되는지 확인합니다.

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 경로와 일치시켜야 합니다.

InboundEmailMessage와 마찬가지로, 웹 앱 핸들러 BounceNotificationHandlerreceive() 메서드를 재정의하여 Python 2용 BounceNotification 클래스에 액세스할 수 있었습니다.

Python 3에서 앱은 사용되는 Python 웹 프레임워크에 따라 여러 가지 방법으로 만들 수 있는 BounceNotification 객체를 인스턴스화해야 합니다.

웹 프레임워크

BounceNotification 객체는 post_vars.get(key)을 호출하여 검색된 값으로 초기화됩니다.

Flask 또는 Django와 같은 Python 웹 프레임워크를 사용하는 경우 BounceNotification 생성자는 양식 데이터의 POST 요청이 포함된 post_vars라는 사전을 사용합니다. 데이터를 검색하려면 입력 객체에서 get() 메서드를 정의해야 합니다. keyBounceNotification에서 읽고 검색할 수 있는 입력 값의 목록이며 다음 중 하나일 수 있습니다.

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']})입니다. 모든 필드의 기본값은 빈 문자열입니다. 이러한 값은 originalnotification 속성을 채웁니다.

raw-message 키의 경우 값이 EmailMessage 생성자에 유효하게 입력되어야 합니다. 단일 값이나 단일 값 목록일 수 있습니다. 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() 메서드는 키에 값이 여러 개 있더라도 한 개의 값만 반환합니다.

키에 해당하는 모든 값을 가져오려면 앱에서 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() 메서드는 키에 값이 여러 개 있더라도 한 개의 값만 반환합니다.

키에 해당하는 모든 값을 가져오려면 앱에서 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 3에서는 from_environ이라는 팩토리 메서드가 BounceNotification에 정의되어 있습니다. 이 메서드는 WSGI environ 사전을 입력으로 사용하는 클래스 메서드이며 모든 WSGI 애플리케이션에 사용될 수 있습니다.

다음 예시에서는 bounce_message를 가져오기 위해 environ이 입력으로 어떻게 사용되는지 확인합니다.

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를 참조하세요.