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 adnotacjami z prośbą o potwierdzenie subskrypcji listy adresowej 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 dla swojego projektu. Umieść w tym katalogu wszystkie pliki aplikacji.

Skopiuj ten kod do pliku o nazwie app.yaml i zastąp zmienną {{ APPID }} 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 plik o nazwie main.py w folderze projektu App Engine i skopiuj ten kod, aby skonfigurować moduły obsługi zbierania i wyświetlania subskrypcji oraz wysyłania e-maili z adnotacjami:

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

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

Możesz dodać uporządkowane dane w jednym z obsługiwanych formatów (JSON-LD lub mikrodane) do parametru head e-maila, aby zdefiniować restaurację i dodać element OneClickAction. Gmail obsługuje OneClickAction i wyświetla użytkownikom specjalny interfejs, aby mogli potwierdzić subskrypcję z poziomu skrzynki odbiorczej.

Skopiuj te znaczniki 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ę adresową o nazwie „XYZ” i ConfirmAction. Modułem obsługi tego działania jest HttpActionHandler, który wysyła żądania POST na adres URL podany we właściwości url.

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

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)

Klasa EmailSender wymaga zalogowania się, aby użytkownik był zalogowany, aby można było pobrać jego adres e-mail. Następnie wczytuje treść e-maila z domeny mail_template.html, zastępuje w nim zmienną confirm_url głównym adresem URL aplikacji App Engine (https://APP-ID.appspot.com) i wysyła e-maila do obecnie zalogowanego użytkownika.

Zbieranie i wyświetlanie listy 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 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`, który odpowiada użytkownikowi, jak w tym przykładzie:

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

Moduł obsługi żądań sprawdza, czy wymagany identyfikator user_id jest zdefiniowany, a potem zapisuje subskrypcję w Datastore. Spowoduje to wysłanie kodu odpowiedzi HTTP 200 z powrotem do Gmaila, aby zasygnalizować, że żądanie zostało zrealizowane. Jeśli żądanie nie zawiera wymaganego pola, moduł obsługi żądania zwróci kod odpowiedzi HTTP 400, sygnalizując, że żądanie jest nieprawidłowe.

Żądania GET wysyłane do głównego adresu URL aplikacji są używane do wyświetlania listy zebranych subskrypcji. Moduł obsługi żądań najpierw pobiera wszystkie subskrypcje z Datastore, a potem wyświetla je na stronie razem z prostym licznikiem.

Testowanie aplikacji

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

Czynności w Gmailu

Gdy wdrożysz aplikację i dodasz subskrypcje, otwórz ją na https://APP-ID.appspot.com, aby zobaczyć stronę z podsumowaniem subskrypcji