Receiving Emailについて質問です。

674 views
Skip to first unread message

naoki

unread,
Oct 22, 2009, 9:48:54 AM10/22/09
to Google-App-Engine-Japan
http://code.google.com/intl/en/appengine/docs/java/mail/receiving.html
を参考に設定を行い、

http://localhost:8080/_ah/admin/inboundmail よりメール受信のテストを行っております。



HttpServletにて受け取ったMimeMessageの、Content-Typeがmultipart/alternativeであるた
め、
Multipartにキャストする必要があると考えております。

しかし、MimeMessageのContentが、
java.io.ByteArrayInputStreamであるためキャストできません。

情報をお持ちの方、いらっしゃいましたらご教示ください。


ちなみに、
ObjectInputStreamを利用して、デシリアライズを試みましたが、
「invalid stream header」(無効なストリームヘッダ)となりました。


以上、よろしくお願いします。





Daisuke Yamashita

unread,
Oct 23, 2009, 12:05:49 AM10/23/09
to google-app-...@googlegroups.com
山下@SOBAプロジェクトです。

サンプル通りにされたのであれば、getContent()でメール本体がByteArrayInputStreamで
取得できるので正しいです。

このストリームにはメールのボディ部が入っていますので、Multipartにキャストする必要はなく、
通常のメールと同じようにパースすればメール本文でも添付ファイルでも取り出す事ができます。

2009/10/22 naoki <naoki...@gmail.com>:
--
Daisuke Yamashita

m seleron

unread,
Oct 25, 2009, 12:19:30 PM10/25/09
to Google-App-Engine-Japan
はじめまして
mimeMessageからMultipartに変換する方法を調べてみましたので
(GAEではなくJavamailの話ではありますが・・・)


mimeMessage = new MimeMessage(session, req.getInputStream());

//以下どちらの方法でもMimeMultipartへの変換は、
//できてはいるようです。
//詳細な内容までは・・・
//-------------------------------------------------------------

DataHandler dataHandler = mimeMessage.getDataHandler();
DataSource dataSource = dataHandler.getDataSource();
MimeMultipart mimeMultipart = new MimeMultipart(dataSource);

or

InputStream inputStream = (InputStream)mimeMessage.getContent();
String ContentType = mimeMessage.getContentType();
ByteArrayDataSource byteArrayDataSource = new ByteArrayDataSource
(inputStream,ContentType);
Multipart mimeMultipart = new MimeMultipart(byteArrayDataSource);

//-------------------------------------------------------------

//http://localhost:8080/_ah/admin/inboundmail からのメールは、
 //[multipart/alternative]ですので、HTMLメールとtextメール2つが取得できます。

 //1つめ
Part part1 = mimeMultipart.getBodyPart(0);
part1.getContentType();
....................
 //2つめ
Part part2 = mimeMultipart.getBodyPart(1);
part2.getContentType();
....................


MimeMultipartへの変換ができるところまでしか
確認できておらず中途半端で申し訳ございませんが、
何かのお役に立てれば幸いです。

naoki

unread,
Oct 26, 2009, 8:44:48 AM10/26/09
to Google-App-Engine-Japan
情報提供頂いた方々ありがとうございます。
提供頂いた情報を基に、以下のようなクラスを作成しましたので、お知らせ致します。

手法としては、mimeMessage.getContent()で取得したByteArrayInputStreamを、
ByteArrayDataSource に変換して、MimeMultipartを生成する。

その後は、通常のメール処理でOKといった感じです。

ありがとうございました!


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);

naoki

unread,
Oct 27, 2009, 9:39:24 AM10/27/09
to Google-App-Engine-Japan
上記のソースが見辛いので、ブログにまとめてみました。
よかったらご参照ください。

http://d.hatena.ne.jp/gungnir_odin/20091026

m seleron

unread,
Dec 3, 2009, 4:52:06 AM12/3/09
to Google-App-Engine-Japan
お気付きの方もいらっしゃると思いますが、
本日、multipart/*のメールを受信したところ

(InputStream)mimeMessage.getContent();
の処理でCast Exceptionが発生しました。

multipart/*のメールを受信した際の
getContent()の戻り値がInputStreamからMultipartに変わっているようです。

対応としては、
・getContentからMimeMultipartへの変換処理を以下のように直接キャストする形へ変更
Multipart content = (Multipart)part.getContent();

・厳密に行うのであれば(必要ないかもしれませんが)
 instanceofで型を確認する。
if (message.getContent() instanceof Multipart)
{
Multipart content = (Multipart)part.getContent();
}

というような変更が必要になるかと思います。

本番環境のバージョンはわかりませんが、
ローカル環境にて、
GAE/JのSDK1.2.8プレリリース版でも同様の内容は確認できるようです。

On 10月27日, 午後10:39, naoki <naoki.wa...@gmail.com> wrote:
> 上記のソースが見辛いので、ブログにまとめてみました。
> よかったらご参照ください。
>
> http://d.hatena.ne.jp/gungnir_odin/20091026

naoki

unread,
Dec 4, 2009, 1:25:03 AM12/4/09
to Google-App-Engine-Japan
本日、本番環境にて動作を確認しました。

getContent()にて取得される型は、
javax.mail.internet.MimeMultipartになっていることを確認しました。

指摘がなければ、気付かないままサービスを提供を続けていました。
ありがとうございました。
Reply all
Reply to author
Forward
0 new messages