以下の組み合わせで動作を確認しています
- jruby-1.4.0
- rails 2.3.2
- appengine-java-sdk-1.3.0.zip
- appengine-apis-0.0.11.jar (0.0.12 でもメール受信部分の機能は入っていないっぽい)
GAE/J でのメールの受信の流れは以下のようになっています。
- (string)@(appid).appspotmail.com 宛へメールを送る
- 次のURLが呼び出される http://(appid).appspot.com/_ah/mail/(string)@(appid).appspotmail.com
- ↑ の URL に関連付けられた method が呼び出される
- TomCat(?) の HttpServletRequest req の req.getInputStream() から受信したメールを読み込む
※ (string)には好きな文字列、(appid)には GAE の appid が入ります。
Java でメールを読み込む部分のサンプルは以下のような感じになります。
Receiving Email – Google App Engine – Google Code
import java.io.IOException; import java.util.Properties; import javax.mail.Session; import javax.mail.internet.MimeMessage; import javax.servlet.http.*; public class MailHandlerServlet extends HttpServlet { public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException { Properties props = new Properties(); Session session = Session.getDefaultInstance(props, null); MimeMessage message = new MimeMessage(session, req.getInputStream());
特に GAE 用の API を呼び出しているわけでもなく、HttpServletRequest にアクセスしているだけです。
ただ jruby の場合、HttpServletRequest のインスタンスが見あたりません・・・。
なので、少しトリッキーなことをして HttpServletRequest のインスタンスを取ってくる必要があります。
rails 2.3.2 で動作確認をしていますので、sinatora などの場合、HttpServletRequest を取ってくる辺りの処理を変更する必要があるかも知れません。(未確認)
それが↓のコード appengine_mail_ext.rb になります。
以下のエントリーの Java のコードを参考にさせていただきました。
Google App Engine for Javaでのメール受信コード – きしだのはてな
appengine_mail_ext.rb
# -*- coding: utf-8 -*- begin module AppEngine module Mail import com.google.appengine.api.mail.MailServiceFactory import com.google.appengine.api.mail.MailService import java.io.IOException import java.io.InputStreamReader import java.io.BufferedReader import java.util.Properties import javax.mail.Message import javax.mail.Session import javax.mail.internet.MimeMessage import javax.servlet.http.HttpServletRequest import javax.servlet.http.HttpServletResponse module_function def java_servlet_request(controller) begin url = controller.instance_variable_get(:@url) req = url.instance_variable_get(:@request) env = req.instance_variable_get(:@env) java_servlet_request = env['java.servlet_request'] rescue raise "java.servlet_request not found." end return java_servlet_request end def receive(java_servlet_request) props = Properties.new session = Session.getDefaultInstance(props, nil) message = MimeMessage.new(session, java_servlet_request.getInputStream()) return nil if message.nil? mail = { :subject => message.get_subject, :content_type => message.get_content_type, } mail[:from] = message.get_from[0].to_string rescue nil mail[:to] = message.get_recipients(Message::RecipientType::TO).map {|address| address.to_string } rescue nil mail[:cc] = message.get_recipients(Message::RecipientType::CC).map {|address| address.to_string } rescue nil mail[:bcc] = message.get_recipients(Message::RecipientType::BCC).map {|address| address.to_string } rescue nil if message.is_mime_type('text/plain') mail[:content] = message.get_content elsif message.mime_type?('multipart/alternative') content = message.get_content (0..(content.count-1)).each do |i| bp = content.get_body_part(i) if bp.mime_type?("text/plain") r = InputStreamReader.new(bp.get_input_stream) buf = BufferedReader.new(r) msg = '' while line = buf.read_line msg << line + "\n" end mail[:content] = msg break end end else raise "unknown content type." end return mail end end end rescue NameError #LoadError # appengine api wasn't available so neither can the store be # This will occur when run script/* end
この appengine_mail_ext.rb を config/environment.rb 内で require するか、
config/initializers へコピーすることで、
AppEngine::Mail が拡張され、メール受信の準備が整います。
(AppEngine::Mail へ受信の method をつっこんでよかったのかなぁ・・・)
次に、メールを受信する部分のコードを action に書いてメール受信処理が完了します。
http://(appid).appspot.com/_ah/mail/(username)@(appid).appspotmail.com へのアクセスを action につなげる部分は、
Java では web.xml に書きますが、GAE/J + jruby + rails の場合、いつも通り config/routes.rb を編集すればいいようです。
以下は MailHandleController#receive へ割り当てた例:
ActionController::Routing::Routes.draw do |map| # ... map.mail '_ah/mail/:email', :controller => 'mail_handle', :action => 'receive', :email => /.*/
最後に、メールを受信するコントローラーとアクションを書いて完了です。
↓はメールを受信して、それをログに表示するサンプル。
class MailHandleController < ApplicationController def receive email = params[:email] # guess_gmail(params[:email]) mail = AppEngine::Mail.receive(AppEngine::Mail.java_servlet_request(self)) Rails.logger.debug("email : #{email}") Rails.logger.debug("mail[:content] : #{mail[:content]}") Rails.logger.debug("mail[:subject] : #{mail[:subject]}") Rails.logger.debug("mail[:from] : #{mail[:from]}") Rails.logger.debug("mail[:to] : #{mail[:to]}") Rails.logger.debug("mail[:cc] : #{mail[:cc]}") Rails.logger.debug("mail[:bcc] : #{mail[:bcc]}") render :text => "mail received.\n" end end
おしまい。

