この記事では、受信トレイから直接メーリング リストの購読を確認するよう求める注釈付きのメールを送信し、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 both
POSTand
GETrequests sent to the app root url (
https://APP-ID.appspot.com).
POSTrequests are used by Gmail to insert new subscriptions including the
user_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 に置き換えます)にアクセスして、アノテーション付きのメールを自分に送信します。
アプリをデプロイして定期購入を挿入したら、https://APP-ID.appspot.com
のアプリにアクセスして、定期購入をまとめたページを取得します。