דוגמה מקצה לקצה

מאמר זה מסביר איך ליצור אפליקציית App Engine ב-Python ששולחת אימיילים עם הערות למשתמשים שמבקשים מהם לאשר הרשמה לרשימת דיוור ישירות מתיבת הדואר הנכנס שלהם, ואוספת את המינויים ב-Datastore.

דרישות מוקדמות והגדרת פרויקט

מדריך זה מבוסס על ההנחה שכבר התקנת את App Engine SDK ושאתה יודע כיצד ליצור, להפעיל ולפרסם פרויקטים של App Engine.

תחילה, צרו ספרייה לפרויקט שלכם. צריך לשמור את כל הקבצים של האפליקציה בספרייה הזו.

יש להעתיק את הקוד הבא לקובץ בשם app.yaml ולהחליף את ה-placeholder {{ APPID }} במזהה האפליקציה הייחודי שלך ב-App Engine:

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

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

libraries:
- name: jinja2
  version: latest

צריך ליצור קובץ בשם main.py בתיקיית הפרויקט של App Engine ולהעתיק את הקוד הבא כדי להגדיר את רכיבי ה-handler לאיסוף ולרישום של מינויים ולשליחת אימיילים עם הערות:

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 ומציג ממשק משתמש ספציפי למשתמשים כדי לאפשר להם לאשר את המינוי מתיבת הדואר הנכנס שלהם.

מעתיקים את תגי העיצוב הבאים לקובץ בשם 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. ה-handler של הפעולה הוא HttpActionHandler ששולח בקשות POST לכתובת ה-URL שצוינה בנכס url.

שליחת בקשות הרשמה למשתמשים

מעתיקים את הקוד הבא לקובץ בשם emailsender.py בתיקיית הפרויקט של App Engine:

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, תחליף את ה-placeholder confirm_url בכתובת ה-URL הבסיסית של אפליקציית App Engine (https://APP-ID.appspot.com) ותשלח את האימייל למשתמש המחובר הנוכחי בתור עצמו.

איסוף ופרסום של מינויים

מעתיקים את הקוד הבא לקובץ בשם subscribe.py בתיקיית הפרויקט של App Engine:

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

handler של הבקשות פשוט בודק שה-user_id הנדרש מוגדר, ואז מאחסן את המינוי ב-Datastore. כתוצאה מכך, קוד התגובה HTTP 200 נשלח בחזרה ל-Gmail כדי לציין שהבקשה בוצעה בהצלחה. אם הבקשה לא כוללת את שדה החובה, ה-handler של הבקשות יחזיר קוד תגובה מסוג HTTP 400, שיעיד על הבקשה הלא חוקית.

בקשות של GET לכתובת ה-URL הבסיסית של האפליקציה משמשות לרשימת המינויים שנאספו. הגורם המטפל בבקשות מאחזר תחילה את כל המינויים מ-Datastore, ולאחר מכן מדפיס אותם בדף, יחד עם מונה פשוט.

בדיקת האפליקציה

פרוס את האפליקציה שלך ב-App Engine ובקר בכתובת https://APP-ID.appspot.com/email (צריך להחליף את APP-ID במזהה האפליקציה של App Engine) כדי לשלוח לעצמך את האימייל עם ההערה.

פעולות ב-Gmail

אחרי שפורסים את האפליקציה ומוסיפים כמה מינויים, צריך להיכנס לאפליקציה בכתובת https://APP-ID.appspot.com כדי לקבל דף עם סיכום של המינויים