엔드 투 엔드 예

이 도움말에서는 사용자에게 받은편지함에서 직접 메일링 리스트 구독을 확인해 달라고 요청하는 주석이 달린 이메일을 보내고 Datastore에 구독을 수집하는 Python으로 App Engine 앱을 빌드하는 방법을 보여줍니다.

기본 요건 및 프로젝트 설정

이 가이드에서는 이미 App Engine SDK를 설치했으며 App Engine 프로젝트를 만들고, 실행하고, 게시하는 방법을 알고 있다고 가정합니다.

먼저 프로젝트의 디렉터리를 만듭니다. 애플리케이션의 모든 파일을 이 디렉터리에 배치합니다.

다음 코드를 app.yaml라는 파일에 복사하고 {{ APPID }} 자리표시자를 고유한 App Engine 앱 ID로 바꿉니다.

application: {{ APPID }}
version: 1
runtime: python27
api_version: 1
threadsafe: true

handlers:
- url: /.*
  script: main.app

libraries:
- name: jinja2
  version: latest

App Engine 프로젝트 폴더에 main.py라는 파일을 만들고 다음 코드를 복사하여 구독을 수집하고 나열하고 주석이 달린 이메일을 보내는 핸들러를 설정합니다.

import webapp2

from emailsender import EmailSender
from subscribe import SubscribeHandler

app = webapp2.WSGIApplication([('/', SubscribeHandler), ('/email', EmailSender)], debug=True)

이메일에 구조화된 데이터 추가

사용자에게 메일링 리스트 구독을 확인해 달라고 요청하는 매우 간단한 이메일로 시작해 보겠습니다.

<html>
  <head>
    <title>Please confirm your subscription to Mailing-List XYZ?</title>
  </head>
  <body>
    <p>
      Dear John, please confirm that you wish to be subscribed to the
      mailing list XYZ
    </p>
  </body>
</html>

지원되는 형식 (JSON-LD 또는 마이크로데이터) 중 하나의 구조화된 데이터를 이메일의 head에 추가하여 식당을 정의하고 OneClickAction을 추가할 수 있습니다. Gmail은 OneClickAction를 지원하며 사용자가 받은편지함에서 구독을 확인할 수 있도록 특정 UI를 표시합니다.

다음 마크업을 mail_template.html 파일에 복사합니다.

JSON-LD

<html>
  <head>
  <title>Please confirm your subscription to Mailing-List XYZ?</title>
  </head>
  <body>
    <script type="application/ld+json">
    {
      "@context": "http://schema.org",
      "@type": "EmailMessage",
      "potentialAction": {
        "@type": "ConfirmAction",
        "name": "Confirm Subscription",
        "handler": {
          "@type": "HttpActionHandler",
          "url": "{{ confirm_url }}",
          "method": "http://schema.org/HttpRequestMethod/POST",
        }
      },
      "description": "Confirm subscription to mailing list XYZ"
    }
    </script>
    <p>
      Dear John, please confirm that you wish to be subscribed to the mailing list XYZ.
    </p>
  </body>
</html>

마이크로데이터

<html>
  <head>
    <title>Please confirm your subscription to Mailing-List XYZ?</title>
  </head>
  <body>
    <div itemscope itemtype="http://schema.org/EmailMessage">
      <div itemprop="potentialAction" itemscope itemtype="http://schema.org/ConfirmAction">
        <meta itemprop="name" content="Approve Expense"/>
        <div itemprop="handler" itemscope itemtype="http://schema.org/HttpActionHandler">
          <link itemprop="url" href="https://myexpenses.com/approve?expenseId=abc123"/>
          <meta itemprop="url" content="{{ confirm_url }}"/>
          <link itemprop="method" href="http://schema.org/HttpRequestMethod/POST"/>
        </div>
      </div>
      <meta itemprop="description" content="Approval request for John's $10.13 expense for office supplies"/>
    </div>
    <p>
      Dear John, please confirm that you wish to be subscribed to the mailing list XYZ.
    </p>
  </body>
</html>

위의 구조화된 데이터는 'XYZ'라는 메일링 리스트와 ConfirmAction를 설명합니다. 작업의 핸들러는 url 속성에 지정된 URL로 POST 요청을 전송하는 HttpActionHandler입니다.

사용자에게 정기 결제 요청 전송

다음 코드를 App Engine 프로젝트 폴더의 emailsender.py 파일에 복사합니다.

import jinja2
import os
import webapp2

from google.appengine.api import mail
from google.appengine.api import users

from urlparse import urlparse

class EmailSender(webapp2.RequestHandler):

  def get(self):
    # require users to be logged in to send emails
    user = users.get_current_user()
    if not user:
      self.redirect(users.create_login_url(self.request.uri))
      return

    email = user.email()

    # The confirm url corresponds to the App Engine app url
    pr = urlparse(self.request.url)
    confirm_url = '%s://%s?user=%s' % (pr.scheme, pr.netloc, user.user_id())

    # load the email template and replace the placeholder with the confirm url
    jinja_environment = jinja2.Environment(
        loader=jinja2.FileSystemLoader(os.path.dirname(__file__)))
    template = jinja_environment.get_template('mail_template.html')
    email_body = template.render({'confirm_url': confirm_url})

    message = mail.EmailMessage(
        sender = email,
        to = email,
        subject = 'Please confirm your subscription to Mailing-List XYZ',
        html = email_body)

    try:
      message.send()
      self.response.write('OK')
    except:
      self.error(500)

EmailSender 클래스는 사용자가 로그인되어 있어야 이메일 주소를 가져올 수 있습니다. 그런 다음 mail_template.html에서 이메일 본문을 로드하고, 본문의 confirm_url 자리표시자를 App Engine 앱의 루트 URL (https://APP-ID.appspot.com)로 바꾸고, 현재 로그인한 사용자에게 본인 이메일로 이메일을 전송합니다.

구독 수집 및 나열

다음 코드를 App Engine 프로젝트 폴더의 subscribe.py 파일에 복사합니다.

import webapp2

from emailsender import EmailSender
from google.appengine.ext import db


class SubscribeHandler(webapp2.RequestHandler):

  def post(self):
    user_id = self.request.get('user')

    # insert the subscription into the Datastore
    subscription = Subscription(user_id=user_id)
    subscription.put()

  def get(self):
    # retrieve up to 1000 subscriptions from the Datastore
    subscriptions = Subscription.all().fetch(1000)

    if not subscriptions:
      self.response.write('No subscriptions')
      return

    count = len(subscriptions)

    for s in subscriptions:
      self.response.write('%s subscribed<br/>' % (s.user_id))

    self.response.write('<br/>')
    self.response.write('%d subscriptions.' % (count))


class Subscription(db.Model):
    user_id = db.TextProperty(required=True)

다음 예와 같이 사용자에 해당하는 SubscribeHandlerclass listens to bothPOSTandGETrequests sent to the app root url (https://APP-ID.appspot.com).POSTrequests are used by Gmail to insert new subscriptions including theuser_id` 매개변수입니다.

https://subscribe.appspot.com/?user_id=123abcd

요청 핸들러는 필요한 user_id가 정의되었는지 확인한 다음 Datastore에 정기 결제를 저장합니다. 그러면 요청이 성공했음을 알리는 HTTP 200 응답 코드가 Gmail로 다시 전송됩니다. 요청에 필수 필드가 포함되지 않은 경우 요청 핸들러는 HTTP 400 응답 코드를 반환하여 잘못된 요청을 알립니다.

앱 루트 URL에 대한 GET 요청은 수집된 구독을 나열하는 데 사용됩니다. 요청 핸들러는 먼저 Datastore에서 모든 구독을 가져온 다음 간단한 카운터와 함께 페이지에 출력합니다.

앱 테스트

App Engine에 앱을 배포하고 https://APP-ID.appspot.com/email (APP-ID를 App Engine 앱 ID로 바꾸기)로 이동하여 주석이 달린 이메일을 나에게 보냅니다.

Gmail의 작업

앱을 배포하고 정기 결제를 삽입한 후 https://APP-ID.appspot.com에서 앱을 방문하여 정기 결제를 요약한 페이지를 확인합니다.