Google App Engine powered python mailer

Third party highly customizable email marketing infrastructure is quiet costly compared to owning dedicate email server. Companies providing low cost email marketing packages has limitation on daily/monthly mail count and bandwidth.  Even there is no guaranty of any hosted mailing server, If internet users mark sent mail/IP as spam, server get black listed. So It’s wise to use trusted mailing infrastructure in budget cost.

Google App Engine allows daily 2000 mail resource usage for free. For more quota one can easily upgrade membership and have reliable and trustful emailing infrastructure.

Google App Engine Mailer Logic Diagram

Features

  1. Django template based mailer
  2. IP address validation/filtering.
  3. Generating PHP API on the fly for remote requests.
  4. Task Queue based mail sending module.

Summary of Application

  • First of all it ask for admin’s google account credentials whenever we point browser to http://appid.appspot.com
  • After successful login, It shows dashboard containing existing created mailer templates.
    Dash Board Screen
  • Admin can add, edit, delete templates. It also allows python django template variables. i.e. Dear {{username}}
    Mailer Edit Screen
  • To get Google App Engine request curl api address, one need to go inside edit mailer.
    Google App Engine Mailer
  • It also allows admin to configure our app for limited IP addresses.
    Mailer IP filter screen

Here is a demo code for Google App Engine Mail task queue

app.yaml

application: your_app
version: 1
runtime: python
api_version: 1

handlers:
- url: /picknsend*
  script: picknsend.py

queue.yaml

queue:
- name: limitedemail
  rate: 2000/d

Setting up task queue

try:
  from google.appengine.api.labs import taskqueue
except ImportError:
  from google.appengine.api import taskqueue # for official inclusion of taskqueue.

 # schedule task queue for sending mail
      q = taskqueue.Queue('limitedemail')
      t = taskqueue.Task(url='/picknsend', method='POST')
      q.add(t)

picknsend.py

#!/usr/bin/env python
# /picknsend task queue job
import os
from google.appengine.ext import webapp
from google.appengine.ext.webapp import util
from google.appengine.ext import db
from google.appengine.api import mail

class MailQueue(db.Model):
  mail_to = db.StringProperty(required=True)
  mail_subject = db.StringProperty(required=True)
  mail_body = db.TextProperty(required=True)
  mail_datetime = db.DateTimeProperty(auto_now_add=True)
  mail_sent = db.BooleanProperty(default=False)

class PickAndSendMail(webapp.RequestHandler):
  def post(self):
    self.sendmail()

  def sendmail(self):
    m = MailQueue.gql("WHERE mail_sent=False ORDER BY mail_datetime asc").fetch(1)
    for i in m:
      BODY    = i.mail_body
      TO      = i.mail_to
      SUBJECT = i.mail_subject
    mail.send_mail('your_email@gmail.com',TO,SUBJECT,BODY)
	for i in m:
      i.mail_sent = True  # marking... mail gone
      i.put()      

def main():
  application = webapp.WSGIApplication([('/picknsend*', PickAndSendMail)], debug=True)
  util.run_wsgi_app(application)

if __name__ == '__main__':
  main()

Above code is not our entire application. It’s just one of the sample module that Google App Engine developer can refer for development.

Python coded GoogleMini SAYT (Search As You Type) run on Google App Engine

One of my client uses GoogleMini for search infrastructure. His entire site was coded in classic asp. I was hired for making some XSLT changes in frontend. GSA 6.0 has built in facility for query auto-completing. But googlemini doesn’t has such facility. So, Google Staff introduce SAYT (search as you type autocomplete) for googlemini and my client asked me to integrate SAYT with his googlemini. Google Mini SAYT is nothing but AJAX autocomplete script written in Javascript and PHP.

My client’s dedicated server is always heavily loaded with daily millions of page-views. So, SAYT was a kind of burden on his server by putting extra load as user keep sending request on every key stroke. Luckily I found Google App Engine, cloud computing infrastructure way cheaper as you can consume 1GB daily bandwidth free of cost. So then I converted GoogleMini SAYT php code into python and created a simple app engine code so we can host and run SAYT from Google Cloud Infrastructure.

# original file search-responder.php is Copyright (C) 2006 Google Inc. under Apache License, Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0

import os
from google.appengine.ext import webapp
from google.appengine.ext.webapp import util
from google.appengine.ext.webapp import template
from django.utils import simplejson

class RPCHandler(webapp.RequestHandler):

  def get(self):
    self.response.headers["Content-Type"] = "text/html; charset=UTF-8"
    self.response.headers["Cache-Control"] = "no-cache"
    self.response.headers.add_header("Expires", "Thu, 01 Dec 1994 16:00:00 GMT")
    # Get the data and the query
    self.data = self.GetData()
    self.query = self.request.get('query').strip().lower()
    # Build Response
    self.responseout = {}
    self.responseout["query"] = self.query
    self.responseout["results"] = self.GetResults()
    if len(self.responseout["results"]) == 1:
      self.responseout["autocompletedQuery"] = self.responseout['results'][0]['name']
    # Output response
    self.response.out.write("searchAsYouType.handleAjaxResponse(")
    self.response.out.write(simplejson.dumps(self.responseout))
    self.response.out.write(");")

  def GetData(self):
    data = []
    data_index = 1
    filedata = open("test-data.txt")
    for line in filedata:
      record = line.strip().split("|")
        if len(record) == 4:
          data.append(record)
    return data

  def GetResults(self):
    results = []
    data = self.data
    queryLength = len(self.query)
    for record in data:
      if record[0].lower().find(self.query,0,queryLength) != -1:
        result = {}
        result['name'] = record[0]
        result['type'] = record[1]
        result['content'] = record[2]
        result['moreDetailsUrl'] = record[3]
        result['style'] = 'expanded' if self.query == record[0].lower() else 'normal'
        results.append(result)
    return results

def main():
  application = webapp.WSGIApplication([('/rpc*', RPCHandler)], debug=True)
  util.run_wsgi_app(application)

if __name__ == '__main__':
main()

Save this code as search-responder.py file, and rest of work is similar to existing setup. Now to run this code from Google App Engine and modify your googlemini custom xslt frontend by these steps.

Note the step:-

<script src="http://localhost/sayt/search-as-you-type.js"></script>

<script>searchAsYouType.initialize(document.getElementById('sayt'), true);</script>

Modify with them with

<script src="http://your-app-engine-path/static_dir/search-as-you-type.js"></script>

<script>searchAsYouType.initialize(document.getElementById('sayt'), true);</script>

Save the Frontend XSLT and you are done.