1 package com.ozacc.mail.impl;
3 import java.io.UnsupportedEncodingException;
5 import java.util.Properties;
7 import javax.mail.Address;
8 import javax.mail.AuthenticationFailedException;
9 import javax.mail.MessagingException;
10 import javax.mail.Session;
11 import javax.mail.Transport;
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.NotConnectedException;
23 import com.ozacc.mail.SendMailPro;
26 * SendMailProインターフェースの実装クラス。
29 * @author Tomohiro Otsuka
30 * @version $Id: SendMailProImpl.java,v 1.4.2.5 2006/08/07 13:45:22 otsuka Exp $
32 public class SendMailProImpl implements SendMailPro {
35 public static final String DEFAULT_PROTOCOL = "smtp";
38 public static final int DEFAULT_PORT = -1;
41 public static final String DEFAULT_HOST = "localhost";
44 public static final String JIS_CHARSET = "ISO-2022-JP";
46 private static final String RETURN_PATH_KEY = "mail.smtp.from";
48 private static Log log = LogFactory.getLog(SendMailProImpl.class);
51 private static final int DEFAULT_CONNECTION_TIMEOUT = 5000;
54 private static final int DEFAULT_READ_TIMEOUT = 5000;
56 private String protocol = DEFAULT_PROTOCOL;
58 private String host = DEFAULT_HOST;
60 private int port = DEFAULT_PORT;
62 private String username;
64 private String password;
66 private String charset = JIS_CHARSET;
68 private String returnPath;
70 private Session session;
72 private Transport transport;
74 private boolean connected;
76 private String messageId;
78 protected int connectionTimeout = DEFAULT_CONNECTION_TIMEOUT;
80 protected int readTimeout = DEFAULT_READ_TIMEOUT;
85 public SendMailProImpl() {}
88 * コンストラクタ。使用するSMTPサーバを指定します。
90 * @param host SMTPサーバのホスト名、またはIPアドレス
92 public SendMailProImpl(String host) {
98 * @see com.ozacc.mail.SendMailPro#connect()
100 public synchronized void connect() throws MailException {
101 if (session == null) {
105 // グローバルReturn-Pathの設定
106 putOnReturnPath(this.returnPath);
110 log.debug("SMTPサーバ[" + host + "]に接続します。");
112 transport = session.getTransport(protocol);
113 transport.connect(host, port, username, password);
114 } catch (AuthenticationFailedException ex) {
115 log.error("SMTPサーバ[" + host + "]への接続認証に失敗しました。", ex);
116 throw new MailAuthenticationException(ex);
117 } catch (MessagingException ex) {
118 log.error("SMTPサーバ[" + host + "]への接続に失敗しました。", ex);
119 throw new MailSendException("SMTPサーバ[" + host + "]への接続に失敗しました。", ex);
122 log.debug("SMTPサーバ[" + host + "]に接続しました。");
129 * {@link #initProperties()} から返された Properties を引数として Session の初期化を行います。
132 private void initSession() {
133 Properties prop = initProperties();
134 session = Session.getInstance(prop);
138 * <p>Session 生成時に渡される Properties オブジェクトを生成して返します。<br>
139 * デフォルトの実装では、タイムアウトおよび SMTP 認証有効化のプロパティを設定しています。<p>
141 * @return 生成した Properties オブジェクト
143 protected Properties initProperties() {
144 Properties prop = new Properties();
146 prop.put("mail.smtp.connectiontimeout", String.valueOf(connectionTimeout));
147 prop.put("mail.smtp.timeout", String.valueOf(readTimeout));
148 // mail.smtp.authプロパティの設定
149 if (username != null && !"".equals(username) && password != null && !"".equals(password)) {
150 prop.put("mail.smtp.auth", "true");
156 * @see com.ozacc.mail.SendMailPro#disconnect()
158 public synchronized void disconnect() throws MailException {
161 log.debug("SMTPサーバ[" + host + "]との接続を切断します。");
167 log.debug("SMTPサーバ[" + host + "]との接続を切断しました。");
168 } catch (MessagingException ex) {
169 log.error("SMTPサーバ[" + host + "]との接続切断に失敗しました。", ex);
170 throw new MailException("SMTPサーバ[" + host + "]との接続切断に失敗しました。");
172 // グローバルReturn-Pathの解除
173 releaseReturnPath(false);
176 log.warn("SMTPサーバ[" + host + "]との接続が確立されていない状態で、接続の切断がリクエストされました。");
185 private void putOnReturnPath(String returnPath) {
186 if (returnPath != null) {
187 session.getProperties().put(RETURN_PATH_KEY, returnPath);
188 log.debug("Return-Path[" + returnPath + "]を設定しました。");
193 * ReturnPathの設定をクリアします。
195 * setGlobalReturnPathAgainがtrueに指定されている場合、一旦Return-Path設定をクリアした後に、
196 * グローバルなReturn-Path(setReturnPath()メソッドで、このインスタンスにセットされたReturn-Pathアドレス)を設定します。
197 * グローバルなReturn-PathがセットされていなければReturn-Pathはクリアされたままになります。
199 * クリアされた状態でsend()メソッドが実行されると、Fromの値がReturn-Pathに使用されます。
201 * @param setGlobalReturnPathAgain Return-Path設定をクリアした後、再度グローバルなReturn-Pathをセットする場合 true
203 private void releaseReturnPath(boolean setGlobalReturnPathAgain) {
204 session.getProperties().remove(RETURN_PATH_KEY);
205 log.debug("Return-Path設定をクリアしました。");
207 if (setGlobalReturnPathAgain && this.returnPath != null) {
208 putOnReturnPath(this.returnPath);
213 * @see com.ozacc.mail.SendMailPro#send(javax.mail.internet.MimeMessage)
215 public void send(MimeMessage mimeMessage) throws MailException {
218 addresses = mimeMessage.getAllRecipients();
219 } catch (MessagingException ex) {
220 log.error("メールの送信に失敗しました。", ex);
221 throw new MailSendException("メールの送信に失敗しました。", ex);
223 processSend(mimeMessage, addresses);
229 private void processSend(MimeMessage mimeMessage, Address[] addresses) {
231 log.error("SMTPサーバへの接続が確立されていません。");
232 throw new NotConnectedException("SMTPサーバへの接続が確立されていません。");
237 mimeMessage.setSentDate(new Date());
238 mimeMessage.saveChanges();
240 log.debug("メールを送信します。");
241 transport.sendMessage(mimeMessage, addresses);
242 log.debug("メールを送信しました。");
243 } catch (MessagingException ex) {
244 log.error("メールの送信に失敗しました。", ex);
245 throw new MailSendException("メールの送信に失敗しました。", ex);
250 * @see com.ozacc.mail.SendMailPro#send(com.ozacc.mail.Mail)
252 public void send(Mail mail) throws MailException {
253 if (mail.getReturnPath() != null) {
254 sendMailWithReturnPath(mail);
261 * 指定されたMailからMimeMessageを生成し、send(MimeMessage)メソッドに渡します。
264 * @throws MailException
266 private void sendMail(Mail mail) throws MailException {
268 MimeMessage message = createMimeMessage();
269 if (isMessageIdCustomized()) {
270 mail.addHeader("Message-ID", ((OMLMimeMessage)message).getMessageId());
272 MimeMessageBuilder builder = new MimeMessageBuilder(message, charset);
274 builder.buildMimeMessage(mail);
275 } catch (UnsupportedEncodingException e) {
276 throw new MailBuildException("サポートされていない文字コードが指定されました。", e);
277 } catch (MessagingException e) {
278 throw new MailBuildException("MimeMessageの生成に失敗しました。", e);
281 if (mail.getEnvelopeTo().length > 0) {
282 log.debug("メールはenvelope-toアドレスに送信されます。");
283 processSend(message, mail.getEnvelopeTo());
290 * 指定されたMailにセットされたReturn-Pathを設定して、メールを送信します。
294 * @throws MailException
296 private synchronized void sendMailWithReturnPath(Mail mail) throws MailException {
297 putOnReturnPath(mail.getReturnPath().getAddress());
301 releaseReturnPath(true);
305 * 新しいMimeMessageオブジェクトを生成します。
307 * @return 新しいMimeMessageオブジェクト
309 public MimeMessage createMimeMessage() {
310 if (isMessageIdCustomized()) {
311 return new OMLMimeMessage(session, messageId);
313 return new MimeMessage(session);
317 * Message-Idヘッダのドメイン部分を独自にセットしているかどうか判定します。
319 * @return Message-Idヘッダのドメイン部分を独自にセットしている場合 true
321 private boolean isMessageIdCustomized() {
322 return messageId != null;
326 * @return Sessionインスタンス
328 protected Session getSession() {
333 * エンコーディングに使用する文字コードを返します。
335 * @return エンコーディングに使用する文字コード
337 public String getCharset() {
342 * メールの件名や本文のエンコーディングに使用する文字コードを指定します。
343 * デフォルトは ISO-2022-JP です。
345 * 日本語環境で利用する場合は通常変更する必要はありません。
347 * @param charset エンコーディングに使用する文字コード
349 public void setCharset(String charset) {
350 this.charset = charset;
354 * @return Returns the host.
356 public String getHost() {
361 * SMTPサーバのホスト名、またはIPアドレスをセットします。
362 * デフォルトは localhost です。
364 * @param host SMTPサーバのホスト名、またはIPアドレス
366 public void setHost(String host) {
371 * @return SMTPサーバ認証パスワード
373 public String getPassword() {
378 * SMTPサーバの接続認証が必要な場合にパスワードをセットします。
380 * @param password SMTPサーバ認証パスワード
382 public void setPassword(String password) {
383 this.password = password;
387 * @return SMTPサーバのポート番号
389 public int getPort() {
394 * SMTPサーバのポート番号をセットします。
396 * @param port SMTPサーバのポート番号
398 public void setPort(int port) {
407 public String getProtocol() {
412 * プロトコルをセットします。デフォルトは「smtp」。
414 * @param protocol プロトコル
416 public void setProtocol(String protocol) {
417 this.protocol = protocol;
421 * @return Return-Pathアドレス
423 public String getReturnPath() {
428 * Return-Pathアドレスをセットします。
430 * 送信するMailインスタンスに指定されたFromアドレス以外のアドレスをReturn-Pathとしたい場合に使用します。
431 * ここでセットされたReturn-Pathより、MailインスタンスにセットされたReturn-Pathが優先されます。
433 * @param returnPath Return-Pathアドレス
435 public void setReturnPath(String returnPath) {
436 this.returnPath = returnPath;
440 * @return SMTPサーバ認証ユーザ名
442 public String getUsername() {
447 * SMTPサーバの接続認証が必要な場合にユーザ名をセットします。
449 * @param username SMTPサーバ認証ユーザ名
451 public void setUsername(String username) {
452 this.username = username;
456 * 生成されるMimeMessageに付けられるMessage-Idヘッダのドメイン部分を指定します。<br>
457 * 指定されない場合(nullや空文字列の場合)は、JavaMailがMessage-Idヘッダを生成します。
458 * JavaMailが生成する「JavaMail.実行ユーザ名@ホスト名」のMessage-Idを避けたい場合に、このメソッドを使用します。
460 * messageIdプロパティがセットされている場合、Mailから生成されるMimeMessageのMessage-Idには
461 * <code>タイムスタンプ + ランダムに生成される16桁の数値 + ここでセットされた値</code>
464 * 生成されるMessage-Idの例。 (実際の数値部分は送信メール毎に変わります)<ul>
465 * <li>messageIdに'example.com'を指定した場合・・・1095714924963.5619528074501343@example.com</li>
466 * <li>messageIdに'@example.com'を指定した場合・・・1095714924963.5619528074501343@example.com (上と同じ)</li>
467 * <li>messageIdに'OML@example.com'を指定した場合・・・1095714924963.5619528074501343.OML@example.com</li>
468 * <li>messageIdに'.OML@example.com'を指定した場合・・・1095714924963.5619528074501343.OML@example.com (上と同じ)</li>
471 * <strong>注:</strong> このMessage-Idは<code>send(Mail)</code>か<code>send(Mail[])</code>メソッドが呼びだれた時にのみ有効です。MimeMessageを直接送信する場合には適用されません。
473 * @param messageId メールに付けられるMessage-Idヘッダのドメイン部分
474 * @throws IllegalArgumentException @を複数含んだ文字列を指定した場合
476 public void setMessageId(String messageId) {
477 if (messageId == null || messageId.length() < 1) {
480 String[] parts = messageId.split("@");
481 if (parts.length > 2) {
482 throw new IllegalArgumentException("messageIdプロパティに'@'を複数含むことはできません。[" + messageId
485 this.messageId = messageId;
489 * SMTPサーバとの接続タイムアウトをセットします。
490 * 単位はミリ秒。デフォルトは5,000ミリ秒(5秒)です。
492 * -1を指定すると無限大になりますが、お薦めしません。
495 * @param connectionTimeout SMTPサーバとの接続タイムアウト
497 public void setConnectionTimeout(int connectionTimeout) {
498 this.connectionTimeout = connectionTimeout;
502 * SMTPサーバへの送受信時のタイムアウトをセットします。
503 * 単位はミリ秒。デフォルトは5,000ミリ秒(5秒)です。
505 * -1を指定すると無限大になりますが、お薦めしません。
508 * @param readTimeout SMTPサーバへの送受信時のタイムアウト
510 public void setReadTimeout(int readTimeout) {
511 this.readTimeout = readTimeout;