Tài liệu này trình bày cách tạo một ứng dụng App Engine bằng Python để gửi email có chú thích cho người dùng yêu cầu xác nhận đăng ký danh sách gửi thư ngay trong hộp thư đến và thu thập các lượt đăng ký trong Datastore.
Điều kiện tiên quyết và cách thiết lập dự án
Hướng dẫn này giả định rằng bạn đã cài đặt App Engine SDK và biết cách tạo, chạy cũng như xuất bản các dự án App Engine.
Trước tiên, hãy tạo một thư mục cho dự án của bạn. Đặt tất cả các tệp cho ứng dụng của bạn vào thư mục này.
Sao chép mã sau vào một tệp có tên app.yaml rồi thay thế phần giữ chỗ {{ APPID }} bằng mã ứng dụng App Engine duy nhất của bạn:
application: {{ APPID }}
version: 1
runtime: python27
api_version: 1
threadsafe: true
handlers:
- url: /.*
script: main.app
libraries:
- name: jinja2
version: latest
Tạo một tệp có tên là main.py trong thư mục dự án App Engine rồi sao chép mã sau để thiết lập trình xử lý cho việc thu thập và liệt kê các lượt đăng ký, cũng như để gửi email có chú thích:
import webapp2
from emailsender import EmailSender
from subscribe import SubscribeHandler
app = webapp2.WSGIApplication([('/', SubscribeHandler), ('/email', EmailSender)], debug=True)
Thêm dữ liệu có cấu trúc vào email
Bắt đầu bằng một email yêu cầu người dùng xác nhận đăng ký nhận email trong danh sách gửi thư:
<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>
Bạn có thể thêm dữ liệu có cấu trúc ở một trong các định dạng được hỗ trợ (JSON-LD hoặc Microdata) vào head của email để xác định nội dung email và thêm OneClickAction.
Gmail hỗ trợ OneClickAction và hiển thị các phần tử giao diện người dùng cho phép người dùng xác nhận việc đăng ký ngay trong hộp thư đến.
Sao chép mã đánh dấu sau đây vào một tệp có tên là 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>
Vi dữ liệu
<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>
Dữ liệu có cấu trúc ở trên mô tả một danh sách gửi thư có tên là "XYZ" và một ConfirmAction. Trình xử lý cho thao tác này là một HttpActionHandler gửi yêu cầu POST đến URL được chỉ định trong thuộc tính url.
Quan trọng: Trong mã trước đó, hãy thay thế phần giữ chỗ {{ confirm_url }} bằng URL của ứng dụng App Engine (chẳng hạn như https://mailing-list.appspot.com) trước khi gửi email. Mã được mô tả trong các bước sau sẽ xử lý việc thay thế này.
Gửi yêu cầu đăng ký cho người dùng
Sao chép mã sau vào một tệp có tên là emailsender.py trong thư mục dự án 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)
Lớp EmailSender yêu cầu người dùng đăng nhập để có thể truy xuất địa chỉ email của họ. Sau đó, hàm này tải nội dung email từ mail_template.html, thay thế phần giữ chỗ confirm_url trong nội dung đó bằng URL gốc của ứng dụng App Engine (https://APP-ID.appspot.com) và gửi email đến người dùng đã đăng nhập.
Thu thập và liệt kê các gói thuê bao
Sao chép mã sau vào một tệp có tên là subscribe.py trong thư mục dự án 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)
Lớp SubscribeHandler xử lý cả yêu cầu POST và GET được gửi đến URL gốc của ứng dụng (https://APP-ID.appspot.com). Gmail dùng yêu cầu POST để chèn các lượt đăng ký mới, bao gồm cả tham số user_id tương ứng với người dùng, như trong ví dụ sau:
https://subscribe.appspot.com/?user_id=123abcd
Trình xử lý yêu cầu kiểm tra để đảm bảo user_id bắt buộc được xác định và lưu trữ gói thuê bao trong Datastore.
Thao tác này sẽ gửi mã phản hồi HTTP 200 trở lại Gmail để báo hiệu yêu cầu thành công. Nếu yêu cầu không bao gồm trường bắt buộc, trình xử lý yêu cầu sẽ trả về mã phản hồi HTTP 400, báo hiệu yêu cầu không hợp lệ.
Các yêu cầu GET đối với danh sách URL gốc của ứng dụng sẽ liệt kê những gói thuê bao đã được thu thập. Trình xử lý yêu cầu tìm nạp tất cả các lượt đăng ký từ Datastore và hiển thị chúng trên trang cùng với một bộ đếm.
Kiểm thử ứng dụng
Triển khai ứng dụng của bạn vào App Engine và truy cập vào https://APP-ID.appspot.com/email (thay thế APP-ID bằng mã ứng dụng App Engine của bạn) để gửi email có chú thích cho chính mình.

Sau khi triển khai ứng dụng và chèn gói thuê bao, hãy truy cập vào ứng dụng của bạn tại https://APP-ID.appspot.com để xem trang tóm tắt các gói thuê bao.