JavaMailでのメール送信まとめその2
JavaMailでのメール送信まとめその2
JavaMailで携帯メール
ここでは携帯メールメッセージの作成方法。
携帯向けメールの注意点
携帯向けメールを送信するときは次の点を注意する必要があります。
- MIME構造が特殊
テキストメール以外の場合、携帯キャリアによってMIME構造が異なります。
- メールアドレスがRFC違反を起こしている
Web屋のネタ帳さんのRFCを読まなかった携帯キャリアの罪に詳しくのっています。
対処として、メールアドレスの@より前をダブルクオートで囲みます。
aaa..@docomo.ne.jp -> "aaa.."@docomo.ne.jp
例えばドコモの場合は、「docomo.ne.jp」でDNSを引いて取得したMXレコードの「mfsmax.docomo.ne.jp」を指定する必要があります。
- 絵文字対応
メール本文に絵文字バイナリを含める場合、Stringクラスを使用できません。
- メールのサイズ
AUなど、添付ファイルのサイズの制限が厳しい端末があります。
- SPFレコードに送信アドレスを登録
なりすまし拒否の対応や、メール不達時にエラーメールを受け取れるようにするため、SPFを設定する必要があります。
docomo
au
softbank
- 送信流量制限
メールの送信数/秒が大きい場合、キャリアによって送信をブロックされることがあります。
docomoの場合は8通/秒くらいまでいけますが、softbankの場合は、2通/秒くらいに抑える必要があります。また、AUの場合は30分単位で規制をかけているようです。
- AUの仕様がよく変わる
いつのまにかブロックされているので注意が必要です。
docomo
テキストメール
docomo携帯にテキストのみのメールを送るサンプル。
- MIME構造
text/plain
- MimeMessage作成サンプル
Properties props = new Properties(); Session session = Session.getDefaultInstance(props); MimeMessage msg = new MimeMessage(session); msg.setSubject("DOCOMO向けテキストメール", "shift-jis"); msg.setFrom(new InternetAddress("from@excample.com")); msg.setSender(new InternetAddress("sender@example.com")); msg.setRecipient(Message.RecipientType.TO, new InternetAddress("to@excample.com")); msg.setDataHandler(new DataHandler(new TextBinaryDataSource("絵文字バイナリを含むmail本文[:1025:][:0105:]".getBytes(), "shift-jis", "plain"))); msg.setHeader("Content-Transfer-Encoding", "base64"); return msg;
- メール内容
From: from@excample.com Sender: sender@example.com To: to@excample.com Message-ID: <11626165.01302146088049.JavaMail.hoge@hoge> Subject: =?shift-jis?B?RE9DT01PjPyCr4Nlg0yDWINng4GBW4OL?= MIME-Version: 1.0 Content-Type: text/plain; charset=shift-jis Content-Transfer-Encoding: base64 ikeVto6ag2+DQ4Npg4qC8Ircgt5tYWlslnuVtvi3+XI=
■注意点
- サブジェクト
MimeMessage#setSubjectでは、絵文字バイナリを含むサブジェクトを指定できません。MimeMessage#setHeaderでMIMEエンコードされたサブジェクトを指定できますが、エンコード処理は自分で実装する必要があります。(JavaMailではMimeUtility#encodeTextでエンコードを行っていますがStringクラスしか扱えません)
サブジェクトに絵文字バイナリを含まないように運用できればいいのですが・・・。
- メール本文
絵文字バイナリを含む場合、Stringクラスを使用できないため、MimeMessage#setTextを使用できません。そのため、DataSource経由でメール本文の文字列をバイナリで提供するようにします。手順的には、ファイルを添付する方法と同じですが、Content-TypeやContent-Transfer-Encodingの指定が異なります。ここでは、以下のようなDataSource継承クラスを作成して対応しています。
import com.ttshrk.mbemoji.Emoji; import com.ttshrk.mbemoji.EmojiUtility; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.UnknownServiceException; import javax.activation.DataSource; public class TextBinaryDataSource implements DataSource { private byte[] text; private byte[] convertedText; private String charset; private String subType; public TextBinaryDataSource(byte[] text, String charset, String subType) throws IOException { this.text = text; this.charset = charset; this.subType = subType; initialize(); } public TextBinaryDataSource(String text, String charset, String subType) throws IOException { this(text.getBytes(), charset, subType); } public byte[] getPlainText() { return text; } private void initialize() throws IOException { InputStream dec_in = new ByteArrayInputStream(text); ByteArrayOutputStream bo = null; OutputStream os = null; try { bo = new ByteArrayOutputStream(); // 必要なら、文字コードや絵文字バイナリコードの変換処理を追加するとよい。 // サンプルとして、ドコモの絵文字に変換してみる。 os = EmojiUtility.decode(bo, charset, Emoji.Mode.DOCOMO); byte[] buf = new byte[2048]; int len; while ((len = dec_in.read(buf)) != -1) { os.write(buf, 0, len); } } finally { if (os != null) { os.close(); } } convertedText = bo.toByteArray(); } @Override public InputStream getInputStream() throws IOException { InputStream is = new ByteArrayInputStream(convertedText); return is; } @Override public OutputStream getOutputStream() throws IOException { throw new UnknownServiceException(); } @Override public String getContentType() { return "text/" + subType + "; charset=" + charset; } @Override public String getName() { return ""; } }
getInputStream | テキストバイナリのInputStreamを返す。 |
getContentType | MIMEヘッダ「Content-Type」で指定する文字列を返す。 |
HTMLメール(インライン画像なし/添付ファイルなし)
docomo携帯にHTMLメール(インライン画像なし/添付ファイルなし)を送るサンプル。
- MIME構造
multipart/mixed └multipart/alternative ├ text/plain └ text/html
- MimeMessage作成サンプル
Properties props = new Properties(); Session session = Session.getDefaultInstance(props); MimeMessage msg = new MimeMessage(session); msg.setSubject("DOCOMO向けHTMLメール(画像無し)送信", "shift-jis"); msg.setFrom(new InternetAddress("from@excample.com")); msg.setSender(new InternetAddress("sender@example.com")); msg.setRecipient(Message.RecipientType.TO, new InternetAddress("to@excample.com")); // mixed Multipart mixedPart = new MimeMultipart("mixed"); // alternative MimeBodyPart alternativeBodyPart = new MimeBodyPart(); Multipart alternativePart = new MimeMultipart("alternative"); alternativeBodyPart.setContent(alternativePart); mixedPart.addBodyPart(alternativeBodyPart); // text mail MimeBodyPart textBodyPart = new MimeBodyPart(); textBodyPart.setDataHandler(new DataHandler(new TextBinaryDataSource("絵文字バイナリを含むmail本文[:1025:][:0105:]".getBytes(), "shift-jis", "plain"))); textBodyPart.setHeader("Content-Transfer-Encoding", "base64"); alternativePart.addBodyPart(textBodyPart); // html mail MimeBodyPart htmlBodyPart = new MimeBodyPart(); htmlBodyPart.setDataHandler(new DataHandler(new TextBinaryDataSource("<HTML><BODY>絵文字バイナリを含むmail本文[:1025:][:0105:]</BODY></HTML>".getBytes(), "shift-jis", "html"))); htmlBodyPart.setHeader("Content-Transfer-Encoding", "base64"); alternativePart.addBodyPart(htmlBodyPart); // set mixed msg.setContent(mixedPart); return msg;
- メール内容
From: from@excample.com Sender: sender@example.com To: to@excample.com Message-ID: <1259414.11302146088111.JavaMail.hoge@hoge> Subject: =?shift-jis?Q?DOCOMO=8C=FC=82=AFHTM?= =?shift-jis?Q?L=83=81=81[=83=8B(=89=E6=91=9C=96=B3=82=B5)=91=97=90M?= MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="----=_Part_0_14746332.1302146088111" ------=_Part_0_14746332.1302146088111 Content-Type: multipart/alternative; boundary="----=_Part_1_8568863.1302146088111" ------=_Part_1_8568863.1302146088111 Content-Type: text/plain; charset=shift-jis Content-Transfer-Encoding: base64 ikeVto6ag2+DQ4Npg4qC8Ircgt5tYWlslnuVtvi3+XKVtg== ------=_Part_1_8568863.1302146088111 Content-Type: text/html; charset=shift-jis Content-Transfer-Encoding: base64 PEhUTUw+PEJPRFk+ikeVto6ag2+DQ4Npg4qC8Ircgt5tYWlslnuVtvi3+XI8L0JPRFk+PC9IVE1M Pg== ------=_Part_1_8568863.1302146088111-- ------=_Part_0_14746332.1302146088111--
HTMLメール(インライン画像あり/添付ファイル無し)
docomo携帯にHTMLメール(インライン画像あり/添付ファイルなし)を送るサンプル。
- MIME構造
multipart/mixed └ multipart/related ├ multipart/alternative │ ├ text/plain │ └ text/html └ image (インライン)
- MimeMessage作成サンプル
Properties props = new Properties(); Session session = Session.getDefaultInstance(props); MimeMessage msg = new MimeMessage(session); msg.setSubject("DOCOMO向けHTMLメール(インライン画像)送信", "shift-jis"); msg.setFrom(new InternetAddress("from@excample.com")); msg.setSender(new InternetAddress("sender@example.com")); msg.setRecipient(Message.RecipientType.TO, new InternetAddress("to@excample.com")); // mixed Multipart mixedPart = new MimeMultipart("mixed"); // related MimeBodyPart relatedBodyPart = new MimeBodyPart(); Multipart relatedPart = new MimeMultipart("related"); relatedBodyPart.setContent(relatedPart); mixedPart.addBodyPart(relatedBodyPart); // alternative MimeBodyPart alternativeBodyPart = new MimeBodyPart(); Multipart alternativePart = new MimeMultipart("alternative"); alternativeBodyPart.setContent(alternativePart); relatedPart.addBodyPart(alternativeBodyPart); // text mail MimeBodyPart textBodyPart = new MimeBodyPart(); textBodyPart.setDataHandler(new DataHandler(new TextBinaryDataSource("絵文字バイナリを含むmail本文".getBytes(), "shift-jis", "plain"))); textBodyPart.setHeader("Content-Transfer-Encoding", "base64"); alternativePart.addBodyPart(textBodyPart); // html mail MimeBodyPart htmlBodyPart = new MimeBodyPart(); htmlBodyPart.setDataHandler(new DataHandler(new TextBinaryDataSource("<HTML><BODY>絵文字バイナリを含むmail本文</BODY></HTML>".getBytes(), "shift-jis", "html"))); htmlBodyPart.setHeader("Content-Transfer-Encoding", "base64"); alternativePart.addBodyPart(htmlBodyPart); // inline image MimeBodyPart imageBodyPart = new MimeBodyPart(); imageBodyPart.setDataHandler(new DataHandler(new FileDataSource("c:/tmp/sample.gif"))); imageBodyPart.setFileName(MimeUtility.encodeWord("sample.gif")); imageBodyPart.setDisposition("inline"); // inline指定しておく imageBodyPart.setContentID("12345@12345"); // インライン画像を指定 relatedPart.addBodyPart(imageBodyPart); // set mixed msg.setContent(mixedPart); return msg;
- メール内容
From: from@excample.com Sender: sender@example.com To: to@excample.com Message-ID: <28027784.21302147855674.JavaMail.hoge@hoge> Subject: =?shift-jis?B?RE9DT01PjPyCr0hUTUyDgYFbg4sog0ODk4OJg0ODk4nmkZwpkZeQTQ==?= MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="----=_Part_2_26094370.1302147855674" ------=_Part_2_26094370.1302147855674 Content-Type: multipart/related; boundary="----=_Part_3_11650554.1302147855674" ------=_Part_3_11650554.1302147855674 Content-Type: multipart/alternative; boundary="----=_Part_4_16270214.1302147855674" ------=_Part_4_16270214.1302147855674 Content-Type: text/plain; charset=shift-jis Content-Transfer-Encoding: base64 ikeVto6ag2+DQ4Npg4qC8Ircgt5tYWlslnuVtg== ------=_Part_4_16270214.1302147855674 Content-Type: text/html; charset=shift-jis Content-Transfer-Encoding: base64 PEhUTUw+PEJPRFk+ikeVto6ag2+DQ4Npg4qC8Ircgt5tYWlslnuVtjwvQk9EWT48L0hUTUw+ ------=_Part_4_16270214.1302147855674-- ------=_Part_3_11650554.1302147855674 Content-Type: image/gif; name=sample.gif Content-Transfer-Encoding: base64 Content-Disposition: inline; filename=sample.gif Content-ID: 12345@12345 R0lGODlhPAA8AJEAAP9nAf9mAP///wAAACH5BAAAAAAALAAAAAA8ADwAAAL/RI6py+0Po5w0iIuz 3rz7LyTgSJabaKYqh66u2r7yGM82i9w6fsCW1sMwVjXaLxMMNXzJUg55bCqZR6c0ea2SiqAYVis1 hrvPyxeoFafJU3MUvP5w5ZazG0313dv8vWnuEST4hpcC2HFmJxQXWGa1yJeVZ1jVIkk5Rgel6GeV 2YhGCDX5BycKicmImPY1lKpX6KZA5Lizc2jrgptLynuz6+vJ+hPW6riwiBw6LLspO6ukvLR8Qtz0 dG092rdabD04uJ3d2c0c7TreF07mfSeyvpf5mWze866NKq/6XB2Pn65PTb8266aB+wZtU71/CFEc fFYkIkN/4irho9OOG0GLTJ3gNcoIkqO6ix8XDgQoch6/QiErumRnkmXKmQJlnpwpzZXCmzxRnTMm UWUwYUN/1SpKSyhSjPuWMnX6AhjUakqnLquANavWrVwZFAAAOw== ------=_Part_3_11650554.1302147855674-- ------=_Part_2_26094370.1302147855674--
HTMLメール(インライン画像あり/添付ファイルあり)
docomo携帯にHTMLメール(インライン画像あり/添付ファイルあり)を送るサンプル。
- MIME構造
multipart/mixed ├ multipart/related │ ├ multipart/alternative │ │ ├ text/plain │ │ └ text/html │ └ image (インライン) └ image (添付)
- MimeMessage作成サンプル
Properties props = new Properties(); Session session = Session.getDefaultInstance(props); MimeMessage msg = new MimeMessage(session); msg.setSubject("DOCOMO向けHTMLメール(インライン画像)送信", "shift-jis"); msg.setFrom(new InternetAddress("from@excample.com")); msg.setSender(new InternetAddress("sender@example.com")); msg.setRecipient(Message.RecipientType.TO, new InternetAddress("to@excample.com")); // mixed Multipart mixedPart = new MimeMultipart("mixed"); // related MimeBodyPart relatedBodyPart = new MimeBodyPart(); Multipart relatedPart = new MimeMultipart("related"); relatedBodyPart.setContent(relatedPart); mixedPart.addBodyPart(relatedBodyPart); // alternative MimeBodyPart alternativeBodyPart = new MimeBodyPart(); Multipart alternativePart = new MimeMultipart("alternative"); alternativeBodyPart.setContent(alternativePart); relatedPart.addBodyPart(alternativeBodyPart); // text mail MimeBodyPart textBodyPart = new MimeBodyPart(); textBodyPart.setDataHandler(new DataHandler(new TextBinaryDataSource("絵文字バイナリを含むmail本文".getBytes(), "shift-jis", "plain"))); textBodyPart.setHeader("Content-Transfer-Encoding", "base64"); alternativePart.addBodyPart(textBodyPart); // html mail MimeBodyPart htmlBodyPart = new MimeBodyPart(); htmlBodyPart.setDataHandler(new DataHandler(new TextBinaryDataSource("<HTML><BODY>絵文字バイナリを含むmail本文</BODY></HTML>".getBytes(), "shift-jis", "html"))); htmlBodyPart.setHeader("Content-Transfer-Encoding", "base64"); alternativePart.addBodyPart(htmlBodyPart); // inline image MimeBodyPart imageBodyPart = new MimeBodyPart(); imageBodyPart.setDataHandler(new DataHandler(new FileDataSource("c:/tmp/sample.gif"))); imageBodyPart.setFileName(MimeUtility.encodeWord("sample.gif")); imageBodyPart.setDisposition("inline"); // inline指定しておく imageBodyPart.setContentID("12345@12345"); // インライン画像を指定 relatedPart.addBodyPart(imageBodyPart); // attachment MimeBodyPart attachBodyPart = new MimeBodyPart(); attachBodyPart.setDataHandler(new DataHandler(new FileDataSource("c:/tmp/sample.gif"))); attachBodyPart.setFileName(MimeUtility.encodeWord("sample.gif")); attachBodyPart.setDisposition("attachment"); // attachment mixedPart.addBodyPart(attachBodyPart); // set mixed msg.setContent(mixedPart); return msg;
- メール内容
From: from@excample.com Sender: sender@example.com To: to@excample.com Message-ID: <12528990.31302148173940.JavaMail.hoge@hoge> Subject: =?shift-jis?B?RE9DT01PjPyCr0hUTUyDgYFbg4sog0ODk4OJg0ODk4nmkZwpkZeQTQ==?= MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="----=_Part_5_26680060.1302148173940" ------=_Part_5_26680060.1302148173940 Content-Type: multipart/related; boundary="----=_Part_6_23910357.1302148173940" ------=_Part_6_23910357.1302148173940 Content-Type: multipart/alternative; boundary="----=_Part_7_13495805.1302148173940" ------=_Part_7_13495805.1302148173940 Content-Type: text/plain; charset=shift-jis Content-Transfer-Encoding: base64 ikeVto6ag2+DQ4Npg4qC8Ircgt5tYWlslnuVtg== ------=_Part_7_13495805.1302148173940 Content-Type: text/html; charset=shift-jis Content-Transfer-Encoding: base64 PEhUTUw+PEJPRFk+ikeVto6ag2+DQ4Npg4qC8Ircgt5tYWlslnuVtjwvQk9EWT48L0hUTUw+ ------=_Part_7_13495805.1302148173940-- ------=_Part_6_23910357.1302148173940 Content-Type: image/gif; name=sample.gif Content-Transfer-Encoding: base64 Content-Disposition: inline; filename=sample.gif Content-ID: 12345@12345 R0lGODlhPAA8AJEAAP9nAf9mAP///wAAACH5BAAAAAAALAAAAAA8ADwAAAL/RI6py+0Po5w0iIuz 3rz7LyTgSJabaKYqh66u2r7yGM82i9w6fsCW1sMwVjXaLxMMNXzJUg55bCqZR6c0ea2SiqAYVis1 hrvPyxeoFafJU3MUvP5w5ZazG0313dv8vWnuEST4hpcC2HFmJxQXWGa1yJeVZ1jVIkk5Rgel6GeV 2YhGCDX5BycKicmImPY1lKpX6KZA5Lizc2jrgptLynuz6+vJ+hPW6riwiBw6LLspO6ukvLR8Qtz0 dG092rdabD04uJ3d2c0c7TreF07mfSeyvpf5mWze866NKq/6XB2Pn65PTb8266aB+wZtU71/CFEc fFYkIkN/4irho9OOG0GLTJ3gNcoIkqO6ix8XDgQoch6/QiErumRnkmXKmQJlnpwpzZXCmzxRnTMm UWUwYUN/1SpKSyhSjPuWMnX6AhjUakqnLquANavWrVwZFAAAOw== ------=_Part_6_23910357.1302148173940-- ------=_Part_5_26680060.1302148173940 Content-Type: image/gif; name=sample.gif Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename=sample.gif R0lGODlhPAA8AJEAAP9nAf9mAP///wAAACH5BAAAAAAALAAAAAA8ADwAAAL/RI6py+0Po5w0iIuz 3rz7LyTgSJabaKYqh66u2r7yGM82i9w6fsCW1sMwVjXaLxMMNXzJUg55bCqZR6c0ea2SiqAYVis1 hrvPyxeoFafJU3MUvP5w5ZazG0313dv8vWnuEST4hpcC2HFmJxQXWGa1yJeVZ1jVIkk5Rgel6GeV 2YhGCDX5BycKicmImPY1lKpX6KZA5Lizc2jrgptLynuz6+vJ+hPW6riwiBw6LLspO6ukvLR8Qtz0 dG092rdabD04uJ3d2c0c7TreF07mfSeyvpf5mWze866NKq/6XB2Pn65PTb8266aB+wZtU71/CFEc fFYkIkN/4irho9OOG0GLTJ3gNcoIkqO6ix8XDgQoch6/QiErumRnkmXKmQJlnpwpzZXCmzxRnTMm UWUwYUN/1SpKSyhSjPuWMnX6AhjUakqnLquANavWrVwZFAAAOw== ------=_Part_5_26680060.1302148173940--