App Engine でメイル受信
1.2.6で追加されたメイルの受信を試してみる.メイル受信機能は,XMPPの受信と同じでWeb hookで実現されている.つまり,メイルが来ると特定のURLに対するアクセスが発生して,それに対応するサーブレットが呼び出される.受信できるメイルアドレスは,
任意の文字列@アプリ名.appspotmail.com
appspot.com ではなく,appspotmail.com であるところに注意.ディスパッチされるURLは
/_ah/mail/アドレス
つまり
/_ah/mail/任意の文字列@アプリ名.appspotmail.com
となる.つまり個々のアドレスに対して別のサーブレットを割り当てることができるわけだが,普通は一つのサーブレットで処理することになるだろう.
メイル受信に必要な行程は以下
appengine-web.xml で宣言
下記をappengine-web.xmlに追記する.このへんは,XMPPの受信と同じ.
<inbound-services> <service>mail</service> </inbound-services>
受信サーブレットのマップ
受信サーブレットをMailHandlerServletという名前だとして,web.xmlにこんな風に書く.
<servlet> <servlet-name>mailhandler</servlet-name> <servlet-class>MailHandlerServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>mailhandler</servlet-name> <url-pattern>/_ah/mail/*</url-pattern> </servlet-mapping>
これだけだと,/_ah/mail/* に通常のHTTPで外部から接続されてしまうので,それを防ぐために下記のように追加.
<security-constraint> <web-resource-collection> <url-pattern>/_ah/mail/*</url-pattern> </web-resource-collection> <auth-constraint> <role-name>admin</role-name> </auth-constraint> </security-constraint>
サーブレットを書く
サーブレットはsmtp2webを使う場合とほとんど同じ.違いは,smtp2webでは,fromとtoをattributeとして取り出してくれたのだけど,appengineはそれをしてくれないというぐらい.サーブレットはこんな感じ.
@SuppressWarnings("serial") public class MailHandlerServlet extends HttpServlet { public void doPost(HttpServletRequest req, HttpServletResponse res) throws IOException { Properties prop = System.getProperties(); Session session = Session.getInstance(prop, null); MimeMessage msg; try { msg = new MimeMessage(session, req.getInputStream()); System.err.println("subject: " + msg.getSubject()); for (Address addr: msg.getFrom()) System.err.println("from:" + addr); for (Address addr: msg.getAllRecipients()) System.err.println("to: " + addr); 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(); } }
追記 2009/12/11 どうも挙動が変わっている.
MimeMessage.getContent()で,以前はInputStreamが返ってきていたのに,今はStringが直接返ってきているようだ.どこのレイヤの変更かはわからない.
private String getText(MimeMessage msg) throws MessagingException{ return (String)msg.getContent(); }
でとりあえず動くようだ.が,本当はgetContent()で返ってくる型をちゃんと見ないといけないよな.反省.