Cet article explique comment créer une application App Engine en Python qui envoie des e-mails annotés aux utilisateurs pour leur demander de confirmer un abonnement à une liste de diffusion directement depuis leur boîte de réception et collecte les abonnements dans le datastore.
Prérequis et configuration du projet
Dans ce guide, nous partons du principe que vous avez déjà installé le SDK App Engine et que vous savez comment créer, exécuter et publier des projets App Engine.
Commencez par créer un répertoire pour votre projet. Placez tous les fichiers de votre application dans ce répertoire.
Copiez le code suivant dans un fichier nommé app.yaml
et remplacez l'espace réservé {{ APPID }}
par l'ID unique de votre application App Engine:
application: {{ APPID }}
version: 1
runtime: python27
api_version: 1
threadsafe: true
handlers:
- url: /.*
script: main.app
libraries:
- name: jinja2
version: latest
Créez un fichier nommé main.py
dans le dossier de votre projet App Engine et copiez le code suivant pour configurer les gestionnaires de collecte et de liste des abonnements, ainsi que pour l'envoi d'e-mails annotés:
import webapp2
from emailsender import EmailSender
from subscribe import SubscribeHandler
app = webapp2.WSGIApplication([('/', SubscribeHandler), ('/email', EmailSender)], debug=True)
Ajouter des données structurées à l'e-mail
Commençons par un e-mail très simple demandant à l'utilisateur de confirmer son abonnement à une liste de diffusion:
<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>
Vous pouvez ajouter des données structurées dans l'un des formats acceptés (JSON-LD ou Microdonnées) au head
de l'e-mail pour définir le restaurant et ajouter une OneClickAction. Gmail est compatible avec OneClickAction
et présente une interface utilisateur spécifique aux utilisateurs pour leur permettre de confirmer leur abonnement depuis leur boîte de réception.
Copiez le balisage suivant dans un fichier nommé 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>
Microdonnées
<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>
Les données structurées ci-dessus décrivent une liste de diffusion appelée "XYZ" et un ConfirmAction
. Le gestionnaire de cette action est un HttpActionHandler
qui envoie des requêtes POST à l'URL spécifiée dans la propriété url
.
Envoyer des demandes d'abonnement aux utilisateurs
Copiez le code suivant dans un fichier nommé emailsender.py
situé dans le dossier du projet 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)
La classe EmailSender
nécessite que l'utilisateur soit connecté pour que son adresse e-mail puisse être récupérée. Ensuite, elle charge le corps de l'e-mail à partir de mail_template.html
, remplace l'espace réservé confirm_url
par l'URL racine de l'application App Engine (https://APP-ID.appspot.com
) et envoie l'e-mail à l'utilisateur actuellement connecté en tant qu'utilisateur.
Collecte et liste des abonnements
Copiez le code suivant dans un fichier nommé subscribe.py
situé dans le dossier du projet 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)
Le paramètre "SubscriptionsHandler"class listens to both
POSTand
GETrequests sent to the app root url (
https://APP-ID.appspot.com).
POSTrequests are used by Gmail to insert new subscriptions including the
user_id correspondant à l'utilisateur, comme dans l'exemple suivant:
https://subscribe.appspot.com/?user_id=123abcd
Le gestionnaire de requêtes vérifie simplement que l'user_id requis est défini, puis stocke l'abonnement dans le Datastore. Un code de réponse HTTP 200
est alors renvoyé à Gmail pour signaler que la requête a abouti. Si la requête n'inclut pas le champ obligatoire, le gestionnaire de requêtes renvoie un code de réponse HTTP 400
pour signaler la requête non valide.
Les requêtes GET
envoyées à l'URL racine de l'application permettent de lister les abonnements collectés. Le gestionnaire de requêtes récupère d'abord tous les abonnements dans le datastore, puis les imprime sur la page, avec un simple compteur.
Tester l'application
Déployez votre application sur App Engine et accédez à https://APP-ID.appspot.com/email
(remplacez APP-ID
par l'ID de votre application App Engine) pour vous envoyer l'e-mail annoté.
Une fois que vous avez déployé votre application et inséré des abonnements, accédez à votre application à l'adresse https://APP-ID.appspot.com
pour obtenir une page récapitulant les abonnements.