Google App Engine(GAE)でメール受信ができるようになりました!
詳しくはこちら
つまるところ、
【[アドレス]@[アプリケーションID].appspotmail.com】宛てにメール受信すると、
【[アプリケーションURL]/_ah/mail/[アドレス]】に対応したサーブレットが起動されるということです。
上のリンク先の下部を確認すると、以下の記述があります。
You can then use various methods to parse the message object:
* Call getContentType() to extract the message content type.
* Call getContentStream() to map the message to a stream object.
* The getContent() method returns an object that implements the Multipart interface. You can then call getCount() to determine the number of parts and getBodyPart(int index) to return a particular body part.
これを踏まえて、通常のメール受信のように、
Properties props = new Properties();
Session session = Session.getDefaultInstance(props, null);
MimeMessage message = new MimeMessage(session, req.getInputStream());
Part p = (Part)messege;
if (p.isMimeType("multipart/*")) { // マルチパートの場合
Multipart mp = (Multipart)p.getContent();
}
なんて素直に書くと、(Multipart)p.getContent()でClassCastExceptionが発生します。
これは、p.getContent()の戻り値が java.io.ByteArrayInputStreamであるためです。
an object that implements the Multipart interface.じゃないのか?
対応としては、以下のようにひと手間加えて、MimeMultipartを生成します。
InputStream inputStream = (InputStream)mimeMessage.getContent(); String ContentType = mimeMessage.getContentType(); ByteArrayDataSource byteArrayDataSource = new ByteArrayDataSource (inputStream,ContentType); Multipart mimeMultipart = new MimeMultipart(byteArrayDataSource);
クラスにまとめたのが、以下のソース。
import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.util.Properties; import javax.mail.MessagingException; import javax.mail.Multipart; import javax.mail.Part; import javax.mail.Session; import javax.mail.internet.MimeMessage; import javax.mail.internet.MimeMultipart; import javax.mail.internet.MimeUtility; import javax.mail.util.ByteArrayDataSource; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.google.appengine.api.datastore.Blob; @SuppressWarnings("serial") public class SampleReceivingMailController extends HttpServlet { /** HTMLメールファイル名 */ private int htmlFileNameCount = 0; @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { try { Properties props = new Properties(); Session session = Session.getDefaultInstance(props, null); MimeMessage message = new MimeMessage(session, req.getInputStream ()); /* メール解析 */ partAnalysis((Part) message); } catch (MessagingException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } /** * メール解析 * * @param part * @throws Exception */ private void partAnalysis(Part part) throws Exception { if (part.isMimeType("multipart/*")) { /* マルチパートの場合 ------------------------------------------------- */ ByteArrayDataSource byteArrayDataSource = new ByteArrayDataSource( (InputStream) part.getContent(), part.getContentType()); Multipart content = new MimeMultipart(byteArrayDataSource); // 含まれるパートを再帰的に処理 int count = content.getCount(); for (int i = 0; i < count; i++) { partAnalysis(content.getBodyPart(i)); } } else if (part.isMimeType("text/plain")) { /* テキストの場合 ----------------------------------------------------- */ InputStream is = (InputStream) part.getInputStream(); Reader r = new InputStreamReader(is); BufferedReader buf = new BufferedReader(r); /* テキスト内容 */ StringBuilder sb = new StringBuilder(); for (String line; (line = buf.readLine()) != null;) { sb.append(line + "\n"); } } else { // その他の場合 /* 添付ファイルを保存 */ getAttachments(part); } } /** * 添付ファイルを取得 * * @param part * @throws MessagingException * @throws IOException */ private void getAttachments(Part part) throws MessagingException, IOException { String disp = part.getDisposition(); if (disp == null || disp.equalsIgnoreCase(Part.ATTACHMENT)) { /* 添付ファイルの場合 --------------------------------------------------- */ /* ファイル名 */ String filename = MimeUtility.decodeText(part.getFileName()); if (part.isMimeType("text/html")) { filename = String.valueOf(htmlFileNameCount++) + ".html"; } /* ファイルサイズ */ int fileSize = part.getSize(); /* コンテントタイプ */ String contentType = part.getContentType(); /* ファイル内容 */ Blob blob = this.generateBlob(part.getInputStream()); } } /** * Blob生成 * @param in * @return Blob * @throws IOException */ private Blob generateBlob(InputStream in) throws IOException{ ByteArrayOutputStream out = new ByteArrayOutputStream(); int len; byte[] buffer = new byte[1024]; while ( (len = in.read(buffer, 0, buffer.length)) != -1) { out.write(buffer, 0, len); } byte[] b = out.toByteArray(); return new Blob(b); } }
メール受信が簡単にできるようになったことで、提供できる機能の幅が広がりましたね!(´∀`)
以上です。
2009/12/04 追記
Google App Engine のバージョンが日本時間の2009/12/03に、1.2.8になったようです。
それに伴って、この記事で書いたクラスが動作しなくなったようです。
こちらで報告されて気がつきました。
2009-12-04 - DISってHONEY♪ @gungnir_odinに修正方法を書きました。