1 package com.ozacc.mail.impl;
3 import java.io.UnsupportedEncodingException;
5 import java.util.Properties;
7 import javax.mail.AuthenticationFailedException;
8 import javax.mail.MessagingException;
9 import javax.mail.Session;
10 import javax.mail.Transport;
11 import javax.mail.internet.InternetAddress;
12 import javax.mail.internet.MimeMessage;
14 import org.apache.commons.logging.Log;
15 import org.apache.commons.logging.LogFactory;
17 import com.ozacc.mail.Mail;
18 import com.ozacc.mail.MailAuthenticationException;
19 import com.ozacc.mail.MailBuildException;
20 import com.ozacc.mail.MailException;
21 import com.ozacc.mail.MailSendException;
22 import com.ozacc.mail.SendMail;
25 * SendMailインターフェースの実装クラス。
28 * @author Tomohiro Otsuka
29 * @version $Id: SendMailImpl.java,v 1.7.2.6 2007/03/30 13:03:44 otsuka Exp $
31 public class SendMailImpl implements SendMail {
33 private static Log log = LogFactory.getLog(SendMailImpl.class);
35 /** デフォルトのプロトコル。「smtp」 */
36 public static final String DEFAULT_PROTOCOL = "smtp";
40 * -1はプロトコルに応じた適切なポートを設定する特別な値。
42 public static final int DEFAULT_PORT = -1;
44 /** デフォルトのSMTPサーバ。「localhost」 */
45 public static final String DEFAULT_HOST = "localhost";
48 public static final String JIS_CHARSET = "ISO-2022-JP";
50 private static final String RETURN_PATH_KEY = "mail.smtp.from";
53 private static final int DEFAULT_CONNECTION_TIMEOUT = 5000;
56 private static final int DEFAULT_READ_TIMEOUT = 5000;
58 private String protocol = DEFAULT_PROTOCOL;
60 private String host = DEFAULT_HOST;
62 private int port = DEFAULT_PORT;
64 private String username;
66 private String password;
68 private String charset = JIS_CHARSET;
70 private String returnPath;
72 private String messageId;
74 private int connectionTimeout = DEFAULT_CONNECTION_TIMEOUT;
76 private int readTimeout = DEFAULT_READ_TIMEOUT;
81 public SendMailImpl() {}
84 * コンストラクタ。使用するSMTPサーバを指定します。
86 * @param host SMTPサーバのホスト名、またはIPアドレス
88 public SendMailImpl(String host) {
94 * @see com.ozacc.mail.SendMail#send(com.ozacc.mail.Mail)
96 public void send(Mail mail) throws MailException {
97 send(new Mail[] { mail });
101 * @see com.ozacc.mail.SendMail#send(com.ozacc.mail.Mail[])
103 public void send(Mail[] mails) throws MailException {
104 MimeMessageWrapper[] mmws = new MimeMessageWrapper[mails.length];
105 Session session = Session.getInstance(new Properties());
106 for (int i = 0; i < mails.length; i++) {
107 Mail mail = mails[i];
110 MimeMessage message = createMimeMessage(session);
111 if (isMessageIdCustomized()) {
112 mail.addHeader("Message-ID", ((OMLMimeMessage)message).getMessageId());
114 MimeMessageBuilder builder = new MimeMessageBuilder(message, charset);
116 builder.buildMimeMessage(mail);
117 } catch (UnsupportedEncodingException e) {
118 throw new MailBuildException("サポートされていない文字コードが指定されました。", e);
119 } catch (MessagingException e) {
120 throw new MailBuildException("MimeMessageの生成に失敗しました。", e);
125 if (mail.getReturnPath() != null) {
126 returnPath = mail.getReturnPath().getAddress();
128 returnPath = this.returnPath;
131 mmws[i] = new MimeMessageWrapper(message, returnPath, mail.getEnvelopeTo());
137 * @see com.ozacc.mail.SendMail#send(javax.mail.internet.MimeMessage)
139 public void send(MimeMessage message) throws MailException {
140 send(new MimeMessage[] { message });
144 * @see com.ozacc.mail.SendMail#send(javax.mail.internet.MimeMessage[])
146 public void send(MimeMessage[] messages) throws MailException {
147 MimeMessageWrapper[] mmws = new MimeMessageWrapper[messages.length];
148 for (int i = 0; i < messages.length; i++) {
149 mmws[i] = new MimeMessageWrapper(messages[i], returnPath);
154 private void processSend(MimeMessageWrapper[] mmws) throws MailException {
156 Properties prop = new Properties();
158 prop.put("mail.smtp.connectiontimeout", String.valueOf(connectionTimeout));
159 prop.put("mail.smtp.timeout", String.valueOf(readTimeout));
160 // mail.smtp.authプロパティの設定
161 if (username != null && !"".equals(username) && password != null && !"".equals(password)) {
162 prop.put("mail.smtp.auth", "true");
164 Session session = Session.getInstance(prop);
166 Transport transport = null;
169 log.debug("SMTPサーバ[" + host + "]に接続します。");
170 transport = session.getTransport(protocol);
171 transport.connect(host, port, username, password);
172 log.debug("SMTPサーバ[" + host + "]に接続しました。");
174 for (int i = 0; i < mmws.length; i++) {
175 MimeMessage mimeMessage = mmws[i].getMimeMessage();
177 String returnPath = mmws[i].getReturnPath();
178 if (returnPath != null) {
179 session.getProperties().put(RETURN_PATH_KEY, returnPath);
180 log.debug("Return-Path[" + returnPath + "]を設定しました。");
183 mimeMessage.setSentDate(new Date());
184 mimeMessage.saveChanges();
187 log.debug("メールを送信します。");
188 if (mmws[i].hasEnvelopeTo()) {
189 log.debug("メールはenvelope-toアドレスに送信されます。");
190 transport.sendMessage(mimeMessage, mmws[i].getEnvelopeTo());
192 transport.sendMessage(mimeMessage, mimeMessage.getAllRecipients());
194 log.debug("メールを送信しました。");
197 if (returnPath != null) {
198 session.getProperties().remove(RETURN_PATH_KEY);
199 log.debug("Return-Path設定をクリアしました。");
202 } catch (AuthenticationFailedException ex) {
203 log.error("SMTPサーバ[" + host + "]への接続認証に失敗しました。", ex);
204 throw new MailAuthenticationException(ex);
205 } catch (MessagingException ex) {
206 log.error("メールの送信に失敗しました。", ex);
207 throw new MailSendException("メールの送信に失敗しました。", ex);
209 if (transport != null && transport.isConnected()) {
210 log.debug("SMTPサーバ[" + host + "]との接続を切断します。");
214 } catch (MessagingException e) {
215 log.error("SMTPサーバ[" + host + "]との接続切断に失敗しました。", e);
216 throw new MailException("SMTPサーバ[" + host + "]との接続切断に失敗しました。");
218 log.debug("SMTPサーバ[" + host + "]との接続を切断しました。");
224 * 新しいMimeMessageオブジェクトを生成します。<br>
225 * messageIdプロパティがセットされている場合、OMLMimeMessageのインスタンスを生成します。
227 * @return 新しいMimeMessageオブジェクト
229 private MimeMessage createMimeMessage(Session session) {
230 if (isMessageIdCustomized()) {
231 return new OMLMimeMessage(session, messageId);
233 return new MimeMessage(session);
237 * Message-Idヘッダのドメイン部分を独自にセットしているかどうか判定します。
239 * @return Message-Idヘッダのドメイン部分を独自にセットしている場合 true
241 private boolean isMessageIdCustomized() {
242 return messageId != null;
246 * エンコーディングに使用する文字コードを返します。
248 * @return エンコーディングに使用する文字コード
250 public String getCharset() {
255 * メールの件名や本文のエンコーディングに使用する文字コードを指定します。
256 * デフォルトは<code>ISO-2022-JP</code>です。
258 * 日本語環境で利用する場合は通常変更する必要はありません。
260 * @param charset エンコーディングに使用する文字コード
262 public void setCharset(String charset) {
263 this.charset = charset;
267 * セットされたSMTPサーバのホスト名、またはIPアドレスを返します。
269 * @return SMTPサーバのホスト名、またはIPアドレス
271 public String getHost() {
276 * SMTPサーバのホスト名、またはIPアドレスをセットします。
277 * デフォルトは localhost です。
279 * @param host SMTPサーバのホスト名、またはIPアドレス
281 public void setHost(String host) {
286 * @return SMTPサーバ認証パスワード
288 public String getPassword() {
293 * SMTPサーバの接続認証が必要な場合にパスワードをセットします。
295 * @param password SMTPサーバ認証パスワード
297 public void setPassword(String password) {
298 this.password = password;
302 * @return SMTPサーバのポート番号
304 public int getPort() {
309 * SMTPサーバのポート番号をセットします。
311 * @param port SMTPサーバのポート番号
313 public void setPort(int port) {
322 public String getProtocol() {
327 * プロトコルをセットします。デフォルトは「smtp」。
329 * @param protocol プロトコル
331 public void setProtocol(String protocol) {
332 this.protocol = protocol;
336 * @return Return-Pathアドレス
338 public String getReturnPath() {
343 * Return-Pathアドレスをセットします。
345 * 送信するMailインスタンスに指定されたFromアドレス以外のアドレスをReturn-Pathとしたい場合に使用します。
346 * ここでセットされたReturn-Pathより、MailインスタンスにセットされたReturn-Pathが優先されます。
348 * @param returnPath Return-Pathアドレス
350 public void setReturnPath(String returnPath) {
351 this.returnPath = returnPath;
355 * @return SMTPサーバ認証ユーザ名
357 public String getUsername() {
362 * SMTPサーバの接続認証が必要な場合にユーザ名をセットします。
364 * @param username SMTPサーバ認証ユーザ名
366 public void setUsername(String username) {
367 this.username = username;
371 * SMTPサーバとの接続タイムアウトをセットします。
372 * 単位はミリ秒。デフォルトは5,000ミリ秒(5秒)です。
374 * -1を指定すると無限大になりますが、お薦めしません。
377 * @param connectionTimeout SMTPサーバとの接続タイムアウト
379 public void setConnectionTimeout(int connectionTimeout) {
380 this.connectionTimeout = connectionTimeout;
384 * SMTPサーバへの送信時のタイムアウトをセットします。
385 * 単位はミリ秒。デフォルトは5,000ミリ秒(5秒)です。<br>
386 * 送信時にタイムアウトすると、<code>com.ozacc.mail.MailSendException</code>がスローされます。
388 * -1を指定すると無限大になりますが、お薦めしません。
391 * @param readTimeout SMTPサーバへの送受信時のタイムアウト
393 public void setReadTimeout(int readTimeout) {
394 this.readTimeout = readTimeout;
398 * 生成されるMimeMessageに付けられるMessage-Idヘッダのドメイン部分を指定します。<br>
399 * 指定されない場合(nullや空文字列の場合)は、JavaMailがMessage-Idヘッダを生成します。
400 * JavaMailが生成する「JavaMail.実行ユーザ名@ホスト名」のMessage-Idを避けたい場合に、このメソッドを使用します。
402 * messageIdプロパティがセットされている場合、Mailから生成されるMimeMessageのMessage-Idには
403 * <code>タイムスタンプ + ランダムに生成される16桁の数値 + ここでセットされた値</code>
406 * 生成されるMessage-Idの例。 (実際の数値部分は送信メール毎に変わります)<ul>
407 * <li>messageIdに'example.com'を指定した場合・・・1095714924963.5619528074501343@example.com</li>
408 * <li>messageIdに'@example.com'を指定した場合・・・1095714924963.5619528074501343@example.com (上と同じ)</li>
409 * <li>messageIdに'OML@example.com'を指定した場合・・・1095714924963.5619528074501343.OML@example.com</li>
410 * <li>messageIdに'.OML@example.com'を指定した場合・・・1095714924963.5619528074501343.OML@example.com (上と同じ)</li>
413 * <strong>注:</strong> このMessage-Idは<code>send(Mail)</code>か<code>send(Mail[])</code>メソッドが呼びだれた時にのみ有効です。MimeMessageを直接送信する場合には適用されません。
415 * @param messageId メールに付けられるMessage-Idヘッダのドメイン部分
416 * @throws IllegalArgumentException @を複数含んだ文字列を指定した場合
418 public void setMessageId(String messageId) {
419 if (messageId == null || messageId.length() < 1) {
423 String[] parts = messageId.split("@");
424 if (parts.length > 2) {
425 throw new IllegalArgumentException("messageIdプロパティに'@'を複数含むことはできません。[" + messageId
429 this.messageId = messageId;
433 * MimeMessageインスタンスと、そのメールに対応するReturn-Path、envelope-toアドレスをラップするクラス。
435 * @author Tomohiro Otsuka
436 * @version $Id: SendMailImpl.java,v 1.7.2.6 2007/03/30 13:03:44 otsuka Exp $
438 private static class MimeMessageWrapper {
440 private MimeMessage mimeMessage;
442 private String returnPath;
444 private InternetAddress[] envelopeTo;
446 public MimeMessageWrapper(MimeMessage mimeMessage, String returnPath) {
447 this.mimeMessage = mimeMessage;
448 this.returnPath = returnPath;
451 public MimeMessageWrapper(MimeMessage mimeMessage, String returnPath,
452 InternetAddress[] envelopeTo) {
453 this.mimeMessage = mimeMessage;
454 this.returnPath = returnPath;
455 this.envelopeTo = envelopeTo;
458 public MimeMessage getMimeMessage() {
462 public String getReturnPath() {
466 public boolean hasEnvelopeTo() {
467 return envelopeTo.length > 0;
470 public InternetAddress[] getEnvelopeTo() {