以下の組み合わせで動作を確認しています
- 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
おしまい。