Contoh menyeluruh

Dokumen ini menunjukkan cara membuat aplikasi App Engine di Python yang mengirim email beranotasi kepada pengguna yang meminta untuk mengonfirmasi langganan milis langsung dari kotak masuk mereka dan mengumpulkan langganan di Datastore.

Prasyarat dan penyiapan project

Panduan ini mengasumsikan bahwa Anda telah menginstal App Engine SDK dan mengetahui cara membuat, menjalankan, dan memublikasikan project App Engine.

Pertama, buat direktori untuk project Anda. Tempatkan semua file untuk aplikasi Anda di direktori ini.

Salin kode berikut ke file bernama app.yaml dan ganti placeholder {{ APPID }}dengan ID aplikasi App Engine unik Anda:

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

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

libraries:
- name: jinja2
  version: latest

Buat file bernama main.py di folder project App Engine Anda dan salin kode berikut untuk menyiapkan pengendali guna mengumpulkan dan mencantumkan langganan, serta untuk mengirim email beranotasi:

import webapp2

from emailsender import EmailSender
from subscribe import SubscribeHandler

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

Menambahkan data terstruktur ke email

Mulai dengan email yang meminta pengguna untuk mengonfirmasi langganan milis:

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

Anda dapat menambahkan data terstruktur dalam salah satu format yang didukung (JSON-LD atau Microdata) ke head email untuk menentukan pesan email dan menambahkan OneClickAction. Gmail mendukung OneClickAction dan menampilkan elemen UI yang memungkinkan pengguna mengonfirmasi langganan mereka dari kotak masuk.

Salin markup berikut ke dalam file bernama 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="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>

Data terstruktur sebelumnya menjelaskan milis bernama "XYZ" dan ConfirmAction. Pengendali untuk tindakan ini adalah HttpActionHandler yang mengirim permintaan POST ke URL yang ditentukan dalam properti url.

Penting: Dalam kode sebelumnya, ganti {{ confirm_url }} placeholder dengan URL aplikasi App Engine Anda (seperti https://mailing-list.appspot.com) sebelum mengirim email apa pun. Kode yang dijelaskan dalam langkah-langkah berikut menangani penggantian ini.

Mengirim permintaan langganan kepada pengguna

Salin kode berikut ke dalam file bernama emailsender.py di folder project 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)

Class EmailSender mengharuskan pengguna untuk login agar alamat email mereka dapat diambil. Kemudian, class ini memuat isi email dari mail_template.html, mengganti placeholder confirm_url di dalamnya dengan URL root aplikasi App Engine (https://APP-ID.appspot.com), dan mengirim email ke pengguna yang login.

Mengumpulkan dan mencantumkan langganan

Salin kode berikut ke dalam file bernama subscribe.py di folder project 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)

Class SubscribeHandler menangani permintaan POST dan GET yang dikirim ke URL root aplikasi (https://APP-ID.appspot.com). Permintaan POST digunakan oleh Gmail untuk menyisipkan langganan baru, termasuk parameter user_id yang sesuai dengan pengguna, seperti dalam contoh berikut:

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

Pengendali permintaan memeriksa apakah user_id yang diperlukan telah ditentukan dan menyimpan langganan di Datastore. Tindakan ini mengirimkan kode respons HTTP 200 kembali ke Gmail untuk menandakan permintaan yang berhasil. Jika permintaan tidak menyertakan kolom yang diperlukan, pengendali permintaan akan menampilkan kode respons HTTP 400, yang menandakan permintaan tidak valid.

Permintaan GET ke URL root aplikasi mencantumkan langganan yang telah dikumpulkan. Pengendali permintaan mengambil semua langganan dari Datastore dan menampilkannya di halaman bersama dengan penghitung.

Menguji aplikasi

Deploy aplikasi Anda ke App Engine dan buka https://APP-ID.appspot.com/email (ganti APP-ID dengan ID aplikasi App Engine Anda) untuk mengirim email beranotasi kepada diri Anda sendiri.

Tindakan di Gmail

Setelah men-deploy aplikasi dan menyisipkan langganan, buka aplikasi Anda di https://APP-ID.appspot.com untuk melihat halaman yang meringkas langganan.