エンドツーエンドの例

この記事では、メールの受信トレイから直接メーリング リストの登録を確認するようユーザーに依頼するアノテーション付きメールを送信し、登録情報を Datastore に収集する App Engine アプリを Python で構築する方法について説明します。

前提条件とプロジェクトの設定

このガイドでは、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 または microdata)の構造化データをメールの 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>

microdata

<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/emailAPP-ID は App Engine アプリ ID に置き換えてください)にアクセスして、アノテーション付きのメールをご自身に送信します。

Gmail での操作

アプリをデプロイして定期購入を挿入したら、アプリ(https://APP-ID.appspot.com)にアクセスして、定期購入の概要ページを表示します。