Google App Engine でメイルの受信
Google App Engine 最大の死角
ここ数ヶ月で急速に整備の進んだGoogle App Engineだが,できて当然なのにまだできていないことがある.メイルの受信だ.メイルの送信はできるし,XMPPの受信だってできるのに,なぜか普通のメイルの受信ができない.GoogleにはGmailという巨大メイルハンドラがあるわけだし,そのうちできるようになるんだろうけど,この話は,それまでのつなぎということで.
smtp2web
smtp2webという無料サービスがある.要するにメイルを受け取ると,それを指定したwebpageへのPOSTアクセスに変換してくれる,というもの.smtp2webのページにも書かれているとおり,App Engine には好適.ソースコードはGoogle codeで公開されているので,その気になれば自分で同じサービスを立ち上げることも可能,とのこと.
さて,使い方をまとめてみよう.基本的には,XXXX@smtp2web.com というアドレスを作らせてくれて,そのアドレスを指定したURLに転送する.どうやら,独自ドメインの転送もできるようだが,それには,そのドメインのDNSのMXをいじる,とかやるんだろう.ここでは単純に,XXXX@smtp2web.com を転送するケースだけ試している.
サインインすると,Googleの認証ページに飛ばされる.OAuthを使ってるのだろう.Gmailのアカウントでログインする.
転送アドレスのドメイン名を聞かれる.ここはデフォルトのsmtp2web.comにしておく.
すると,メイル転送を設定するユーザ名,と転送先URLの指定をうながされる.転送先URLを,appengine上の適当なサーブレットにする.ここでは,http://XXXX.appspot.com/mailHandlerというURLにしている.
ここでもう一段認証が入る.そのURLを使う権利がユーザにあるか?を証明しなければならない.認証は,ユーザが指定したURLの付近に,smtp2webが指定した名前でファイルを作ることで行う.App Engine Java版では,warディレクトリにファイルを置けば,そのまま見えるので簡単.Python版だとスタティックファイルは明示的に指定しなければならないので,ちょっと面倒.
ハンドラサーブレット
これであとは,ハンドルするサーブレットを書いてやればよい.メッセージは,MIME形式でサーブレットのストリームとして与えられるので,これをパーズしてやればよい.やればよいのだが,MIMEが複雑なのと,JavaMailがわけわからないのと,日本語のハンドルが元々面倒という3つ面倒の合わせ技でかなり面倒.
とりあえず,ISO 2022 でplain textのメイルならこんな感じでパーズしてやればよい,はず.JavaMail難しい.
import java.io.*; import java.util.Properties; import javax.servlet.http.*; import javax.mail.*; import javax.mail.internet.MimeMessage; @SuppressWarnings("serial") public class MailHandlerServlet extends HttpServlet { public void doPost(HttpServletRequest req, HttpServletResponse res) throws IOException { System.err.println("from:" + req.getParameter("from")); System.err.println("to: " + req.getParameter("to")); Properties prop = System.getProperties(); Session session = Session.getInstance(prop); MimeMessage msg; try { msg = new MimeMessage(session, req.getInputStream()); System.err.println("subject: " + msg.getSubject()); System.err.println("body: ---->" ); System.err.print (getText(msg)); System.err.println("body: <----" ); } catch (MessagingException e) { e.printStackTrace(); throw new IOException("Message Excetion: " + e.getMessage()); } } private String getText(MimeMessage msg) throws IOException, MessagingException{ InputStream is = (InputStream)msg.getContent(); StringBuffer sb = new StringBuffer(); LineNumberReader lnr = new LineNumberReader(new InputStreamReader(is, "ISO2022JP")); String s = null; while ((s = lnr.readLine()) != null) sb.append(s + "\n"); return sb.toString(); } }
最後に,web.xmlでマッピングを書いてやる.こんなかんじ.
<servlet> <servlet-name>mailhandler</servlet-name> <servlet-class>MailHandlerServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>mailhandler</servlet-name> <url-pattern>/mailHandler</url-pattern> </servlet-mapping>