Kompleksowy przykład

Z tego artykułu dowiesz się, jak utworzyć w Pythonie aplikację App Engine, która wysyła do użytkowników e-maile z prośbą o potwierdzenie subskrypcji listy mailingowej bezpośrednio ze skrzynki odbiorczej i zbiera subskrypcje w Datastore.

Wymagania wstępne i konfiguracja projektu

W tym przewodniku zakładamy, że masz już zainstalowany pakiet SDK App Engine i wiesz, jak tworzyć, uruchamiać i publikować projekty App Engine.

Najpierw utwórz katalog projektu. Umieść w tym katalogu wszystkie pliki związane z aplikacją.

Skopiuj ten kod do pliku o nazwie app.yaml i zastąp miejsce zapełnienia {{ APPID }} swoim unikalnym identyfikatorem aplikacji App Engine:

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

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

libraries:
- name: jinja2
  version: latest

Utwórz w folderze projektu App Engine plik o nazwie main.py i skopiuj do niego podany niżej kod, aby skonfigurować moduły obsługi zbierania i wyświetlania subskrypcji oraz wysyłania opatrzonych adnotacjami e-maili:

import webapp2

from emailsender import EmailSender
from subscribe import SubscribeHandler

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

Dodawanie uporządkowanych danych do e-maila

Zacznijmy od bardzo prostego e-maila z prośbą o potwierdzenie subskrypcji listy mailingowej:

<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>

Aby zdefiniować restaurację i dodać akcję OneClickAction, możesz dodać uporządkowane dane w jednym z obsługiwanych formatów (JSON-LD lub mikrodane) do head e-maila. Gmail obsługuje OneClickAction i wyświetla użytkownikom odpowiedni interfejs, aby umożliwić im potwierdzenie subskrypcji w skrzynce odbiorczej.

Skopiuj ten kod do pliku o nazwie 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>

Mikrodane

<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>

Powyższe uporządkowane dane opisują listę mailingową o nazwie „XYZ” i ConfirmAction. Obsługa działania to HttpActionHandler, który wysyła żądania POST do adresu URL podanego w usłudze url.

Wysyłanie próśb o subskrypcję do użytkowników

Skopiuj ten kod do pliku o nazwie emailsender.py w folderze projektu 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)

Zajęcia EmailSender wymagają zalogowania się użytkownika, aby można było pobrać jego adres e-mail. Następnie wczytuje treść e-maila z mail_template.html, zastępuje w nim placeholder confirm_url adresem URL katalogu / root aplikacji App Engine (https://APP-ID.appspot.com) i wysyła e-maila do aktualnie zalogowanego użytkownika.

Zbieranie i wyświetlanie subskrypcji

Skopiuj ten kod do pliku o nazwie subscribe.py w folderze projektu 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)

Parametr zapytania 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 odpowiadający użytkownikowi, jak w tym przykładzie:

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

Obsługa żądania sprawdza, czy zdefiniowano wymagany identyfikator user_id, a następnie zapisuje subskrypcję w Datasourse. W efekcie do Gmaila zostanie wysłany kod odpowiedzi HTTP 200, który będzie sygnałem, że żądanie zostało zrealizowane. Jeśli żądanie nie zawiera wymaganego pola, moduł obsługujący żądanie zwróci kod odpowiedzi HTTP 400, sygnalizując nieprawidłowe żądanie.

GET żądania do adresu URL katalogu głównego aplikacji służą do wyświetlania zebranych subskrypcji. Obsługa żądania pobiera najpierw wszystkie subskrypcje z Datastore, a potem drukuje je na stronie wraz z prostym licznikiem.

Testowanie aplikacji

Wdróż aplikację w App Engine i wejdź na stronę https://APP-ID.appspot.com/email (zastąp APP-ID identyfikatorem aplikacji App Engine), aby wysłać do siebie e-maila z adnotacjami.

Działania w Gmailu

Po wdrożenie aplikacji i wstawieniu subskrypcji otwórz ją na stronie https://APP-ID.appspot.com, aby wyświetlić stronę z podsumowaniem subskrypcji.