GAEからim.kayac.comを使ってGmailの新着をPush通知

Gmailの新着がAtomフィードとして提供されていることを知ったので作ってみました。Push通知を受けとるアプリもiTunesStoreで販売されていますが、メールの内容をPush通知させるということは外部のサーバにメールの内容(一部?)を送信しているということになるのでそういう心配を回避する為という理由もあります。

Basic認証を使用していますが、httpsのURLなので暗号化経路となり、通信経路上でパスワードが漏洩することはないです。

gdispatch.pyを使っていますが、今回はその機能のほとんどを使用していません(^^;)

# coding: utf-8
import logging

from google.appengine.ext import webapp
from google.appengine.ext import db
from google.appengine.api import urlfetch

import gdispatch
import base64
import time
import urllib
import yaml
from xml.etree import ElementTree as etree

class MessageTime(db.Model):
  time = db.FloatProperty()


def latesttime(id, password):
  auth = base64.encodestring('%s:%s' % (id,password))[:-1]
  headers = {'Authorization': 'Basic %s' % auth}
  url = 'https://mail.google.com/mail/feed/atom/'
  res = urlfetch.fetch(url, '', urlfetch.GET, headers)
  dom = etree.fromstring(res.content)
  namespace = 'http://purl.org/atom/ns#'

  items = dom.findall('.//{%s}entry/{%s}modified' % (namespace,namespace))
  if len(items) < 1:
    return None
  latest = max(map(
    lambda x: time.mktime(time.strptime(x.text, '%Y-%m-%dT%H:%M:%SZ')),
    items))
  return latest

def notifykayac(kayacid,message):
  urlfetch.fetch('http://im.kayac.com/api/post/%s' % kayacid, 'message=%s' % message, urlfetch.POST, {})

gdispatch.route(lambda: ('/.*', MainHandler))
class MainHandler(webapp.RequestHandler):
  @gdispatch.kwargs
  def get(self):
    account = yaml.load(open('gmailaccount.yaml'))
    for ac in account:
      latest = latesttime(ac['id'], ac['password'])
      if latest is None:
        self.response.out.write('no mail')
        continue
      keyname = 'latest_%s' % ac['id']
      t = MessageTime.get_by_key_name(keyname)
      if t is None:
        t = MessageTime(key_name=keyname)
        t.time = 0.0
      if t.time < latest:
        notifykayac(ac['kayacid'],urllib.quote(ac['message'].encode('utf-8')))
        self.response.out.write(ac['message'])
        t.time = latest
        t.put()
  
def main():
  gdispatch.run()

if __name__ == '__main__':
  main()

設定ファイル(gmailaccount.yaml)は複数アカウントに対応しています。

---
- id: GmailAccount1
  password: GmailPassword1
  kayacid: KayacId1
  message: 'メールがきたようだ'
- id: GmailAccount2
  password: GmailPassword2
  kayacid: KayacId1
  message: 'メールチェックだ'


[参考]