Vollständiges Beispiel

In diesem Dokument wird beschrieben, wie Sie eine App Engine-Anwendung in Python erstellen, die annotierte E‑Mails an Nutzer sendet, in denen sie aufgefordert werden, ein Mailinglistenabo direkt in ihrem Posteingang zu bestätigen. Die Abos werden in Datastore erfasst.

Voraussetzungen und Projekteinrichtung

In dieser Anleitung wird davon ausgegangen, dass Sie das App Engine SDK bereits installiert haben und wissen, wie Sie App Engine-Projekte erstellen, ausführen und veröffentlichen.

Erstellen Sie zuerst ein Verzeichnis für Ihr Projekt. Legen Sie alle Dateien für Ihre Anwendung in diesem Verzeichnis ab.

Kopieren Sie den folgenden Code in eine Datei mit dem Namen app.yaml und ersetzen Sie den Platzhalter {{ APPID }} durch Ihre eindeutige App Engine-App-ID:

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

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

libraries:
- name: jinja2
  version: latest

Erstellen Sie in Ihrem App Engine-Projektordner eine Datei mit dem Namen main.py und kopieren Sie den folgenden Code, um die Handler zum Erfassen und Auflisten von Abonnements und zum Senden von E-Mails mit Anmerkungen einzurichten:

import webapp2

from emailsender import EmailSender
from subscribe import SubscribeHandler

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

Strukturierte Daten in die E-Mail einfügen

Beginnen Sie mit einer E‑Mail, in der der Nutzer gebeten wird, die Anmeldung für eine Mailingliste zu bestätigen:

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

Sie können strukturierte Daten in einem der unterstützten Formate (JSON-LD oder Mikrodaten) zum head der E-Mail hinzufügen, um die E-Mail-Nachricht zu definieren und eine OneClickAction hinzuzufügen. Gmail unterstützt OneClickAction und zeigt UI-Elemente an, mit denen Nutzer ihr Abo über den Posteingang bestätigen können.

Kopieren Sie das folgende Markup in eine Datei mit dem Namen 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>

Mikrodaten

<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="Confirm Subscription"/>
        <div itemprop="handler" itemscope itemtype="http://schema.org/HttpActionHandler">
          <meta itemprop="url" content="{{ confirm_url }}"/>
          <link itemprop="method" href="http://schema.org/HttpRequestMethod/POST"/>
        </div>
      </div>
      <meta itemprop="description" content="Confirm subscription to mailing list XYZ"/>
    </div>
    <p>
      Dear John, please confirm that you wish to be subscribed to the mailing list XYZ.
    </p>
  </body>
</html>

Die oben stehenden strukturierten Daten beschreiben eine Mailingliste namens „XYZ“ und eine ConfirmAction. Der Handler für die Aktion ist ein HttpActionHandler, der POST-Anfragen an die in der url-Eigenschaft angegebene URL sendet.

Wichtig: Ersetzen Sie im vorherigen Code den Platzhalter {{ confirm_url }} durch die URL Ihrer App Engine-App (z. B. https://mailing-list.appspot.com), bevor Sie E‑Mails senden. Der in den folgenden Schritten beschriebene Code übernimmt diesen Ersatz.

Aboanfragen an Nutzer senden

Kopieren Sie den folgenden Code in eine Datei mit dem Namen emailsender.py im App Engine-Projektordner:

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)

Für die Klasse EmailSender muss der Nutzer angemeldet sein, damit seine E‑Mail-Adresse abgerufen werden kann. Anschließend wird der E-Mail-Text aus mail_template.html geladen, der Platzhalter confirm_url darin durch die Stamm-URL der App Engine-App (https://APP-ID.appspot.com) ersetzt und die E-Mail an den angemeldeten Nutzer gesendet.

Abos erfassen und auflisten

Kopieren Sie den folgenden Code in eine Datei mit dem Namen subscribe.py im App Engine-Projektordner:

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)

Die Klasse SubscribeHandler verarbeitet sowohl POST- als auch GET-Anfragen, die an die App-Stamm-URL (https://APP-ID.appspot.com) gesendet werden. POST-Anfragen werden von Gmail verwendet, um neue Abos einschließlich des Parameters user_id einzufügen, der dem Nutzer entspricht, wie im folgenden Beispiel:

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

Der Anfrage-Handler prüft, ob das erforderliche user_id definiert ist, und speichert das Abo in Datastore. Dadurch wird ein HTTP 200-Antwortcode an Gmail gesendet, um die erfolgreiche Anfrage zu signalisieren. Wenn die Anfrage das erforderliche Feld nicht enthält, gibt der Anfrage-Handler den Antwortcode HTTP 400 zurück, um die ungültige Anfrage zu signalisieren.

Bei GET-Anfragen an die App-Stamm-URL werden die erhobenen Abos aufgelistet. Der Request-Handler ruft alle Abos aus dem Datastore ab und zeigt sie zusammen mit einem Zähler auf der Seite an.

Anwendung testen

Stellen Sie Ihre App in App Engine bereit und rufen Sie https://APP-ID.appspot.com/email auf (ersetzen Sie APP-ID durch Ihre App Engine-App-ID), um die kommentierte E‑Mail an sich selbst zu senden.

Aktionen in Gmail

Nachdem Sie Ihre App bereitgestellt und Abos eingefügt haben, können Sie unter https://APP-ID.appspot.com eine Seite mit einer Zusammenfassung der Abos aufrufen.