View Javadoc

1   package com.ozacc.mail.impl;
2   
3   import java.io.UnsupportedEncodingException;
4   import java.util.Date;
5   import java.util.Properties;
6   
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.MimeMessage;
12  
13  import org.apache.commons.logging.Log;
14  import org.apache.commons.logging.LogFactory;
15  
16  import com.ozacc.mail.Mail;
17  import com.ozacc.mail.MailAuthenticationException;
18  import com.ozacc.mail.MailBuildException;
19  import com.ozacc.mail.MailException;
20  import com.ozacc.mail.MailSendException;
21  import com.ozacc.mail.NotConnectedException;
22  import com.ozacc.mail.SendMailPro;
23  
24  /***
25   * SendMailProインターフェースの実装クラス。
26   * 
27   * @since 1.0
28   * @author Tomohiro Otsuka
29   * @version $Id: SendMailProImpl.java,v 1.4 2004/09/21 20:54:40 otsuka Exp $
30   */
31  public class SendMailProImpl implements SendMailPro {
32  
33  	/*** smtp */
34  	public static final String DEFAULT_PROTOCOL = "smtp";
35  
36  	/*** -1 */
37  	public static final int DEFAULT_PORT = -1;
38  
39  	/*** localhost */
40  	public static final String DEFAULT_HOST = "localhost";
41  
42  	/*** ISO-2022-JP */
43  	public static final String JIS_CHARSET = "ISO-2022-JP";
44  
45  	private static final String RETURN_PATH_KEY = "mail.smtp.from";
46  
47  	private static Log log = LogFactory.getLog(SendMailProImpl.class);
48  
49  	private String protocol = DEFAULT_PROTOCOL;
50  
51  	private String host = DEFAULT_HOST;
52  
53  	private int port = DEFAULT_PORT;
54  
55  	private String username;
56  
57  	private String password;
58  
59  	private String charset = JIS_CHARSET;
60  
61  	private String returnPath;
62  
63  	private Session session = Session.getInstance(new Properties());
64  
65  	private Transport transport;
66  
67  	private boolean connected;
68  
69  	private String messageId;
70  
71  	/***
72  	 * コンストラクタ。
73  	 */
74  	public SendMailProImpl() {}
75  
76  	/***
77  	 * コンストラクタ。使用す�?SMTPサーバを指定します。
78  	 * 
79  	 * @param host SMTPサーバのホスト名、またはIPアド�?ス
80  	 */
81  	public SendMailProImpl(String host) {
82  		this();
83  		setHost(host);
84  	}
85  
86  	/***
87  	 * @see com.ozacc.mail.SendMailPro#connect()
88  	 */
89  	public synchronized void connect() throws MailException {
90  		// グ��充バ�?Return-Pathの設�?
91  		putOnReturnPath(this.returnPath);
92  
93  		try {
94  			// SMTPサーバに接続
95  			log.debug("SMTPサーバ[" + host + "]に接続します。");
96  
97  			transport = session.getTransport(protocol);
98  			transport.connect(host, port, username, password);
99  		} catch (AuthenticationFailedException ex) {
100 			log.error("SMTPサーバ[" + host + "]への接続認証に失敗しました。", ex);
101 			throw new MailAuthenticationException(ex);
102 		} catch (MessagingException ex) {
103 			log.error("SMTPサーバ[" + host + "]への接続に失敗しました。", ex);
104 			throw new MailSendException("SMTPサーバ[" + host + "]への接続に失敗しました。", ex);
105 		}
106 
107 		log.debug("SMTPサーバ[" + host + "]に接続しました。");
108 
109 		connected = true;
110 	}
111 
112 	/***
113 	 * @see com.ozacc.mail.SendMailPro#disconnect()
114 	 */
115 	public synchronized void disconnect() throws MailException {
116 		if (connected) {
117 			try {
118 				log.debug("SMTPサーバ[" + host + "]との接続を切断します。");
119 
120 				// SMTPサーバとの接続を切断
121 				transport.close();
122 				connected = false;
123 
124 				log.debug("SMTPサーバ[" + host + "]との接続を切断しました。");
125 			} catch (MessagingException ex) {
126 				log.error("SMTPサーバ[" + host + "]との接続切断に失敗しました。", ex);
127 				throw new MailException("SMTPサーバ[" + host + "]との接続切断に失敗しました。");
128 			} finally {
129 				// グ��充バ�?Return-Pathの解�?
130 				releaseReturnPath(false);
131 			}
132 		} else {
133 			log.warn("SMTPサーバ[" + host + "]との接続が確立さ�?ていない状態で、接続の切断が�?クエストさ�?ました。");
134 		}
135 	}
136 
137 	/***
138 	 * ReturnPathをセットします。
139 	 * 
140 	 * @param returnPath
141 	 */
142 	private void putOnReturnPath(String returnPath) {
143 		if (returnPath != null) {
144 			session.getProperties().put(RETURN_PATH_KEY, returnPath);
145 			log.debug("Return-Path[" + returnPath + "]を設定しました。");
146 		}
147 	}
148 
149 	/***
150 	 * ReturnPathの設定をク�?アします。
151 	 * <p>
152 	 * setGlobalReturnPathAgainがtrueに指定さ�?てい�?�?合、�?旦Return-Path設定をク�?アした後に、
153 	 * グ��充バ�?なReturn-Path(setReturnPath()メソッドで、このインスタンスにセットさ�?たReturn-Pathアド�?ス)を設定します。
154 	 * グ��充バ�?なReturn-Pathがセットさ�?ていなけ�?ばReturn-Pathはク�?アさ�?たままになります。
155 	 * <p>
156 	 * ク�?アさ�?た状態でsend()メソッドが実行さ�?�?と、Fromの値がReturn-Pathに使用さ�?ます。
157 	 * 
158 	 * @param setGlobalReturnPathAgain Return-Path設定をク�?アした後、再度グ��充バ�?なReturn-Pathをセットす�?�?�? true
159 	 */
160 	private void releaseReturnPath(boolean setGlobalReturnPathAgain) {
161 		session.getProperties().remove(RETURN_PATH_KEY);
162 		log.debug("Return-Path設定をク�?アしました。");
163 
164 		if (setGlobalReturnPathAgain && this.returnPath != null) {
165 			putOnReturnPath(this.returnPath);
166 		}
167 	}
168 
169 	/***
170 	 * @see com.ozacc.mail.SendMailPro#send(javax.mail.internet.MimeMessage)
171 	 */
172 	public void send(MimeMessage mimeMessage) throws MailException {
173 		if (!connected) {
174 			log.error("SMTPサーバへの接続が確立さ�?ていません。");
175 			throw new NotConnectedException("SMTPサーバへの接続が確立さ�?ていません。");
176 		}
177 
178 		try {
179 			// 送信�?�?をセット
180 			mimeMessage.setSentDate(new Date());
181 			mimeMessage.saveChanges();
182 			// 送信
183 			log.debug("メー�?を送信します。");
184 			transport.sendMessage(mimeMessage, mimeMessage.getAllRecipients());
185 			log.debug("メー�?を送信しました。");
186 		} catch (MessagingException ex) {
187 			log.error("メー�?の送信に失敗しました。", ex);
188 			throw new MailSendException("メー�?の送信に失敗しました。", ex);
189 		}
190 	}
191 
192 	/***
193 	 * @see com.ozacc.mail.SendMailPro#send(com.ozacc.mail.Mail)
194 	 */
195 	public void send(Mail mail) throws MailException {
196 		if (mail.getReturnPath() != null) {
197 			sendMailWithReturnPath(mail);
198 		} else {
199 			sendMail(mail);
200 		}
201 	}
202 
203 	/***
204 	 * 指定さ�?たMailからMimeMessageを生成し、send(MimeMessage)メソッドに渡します。
205 	 * 
206 	 * @param mail
207 	 * @throws MailException
208 	 */
209 	private void sendMail(Mail mail) throws MailException {
210 		// MimeMessageの生成
211 		MimeMessage message = createMimeMessage();
212 		MimeMessageBuilder builder = new MimeMessageBuilder(message, charset);
213 		try {
214 			builder.buildMimeMessage(mail);
215 		} catch (UnsupportedEncodingException e) {
216 			throw new MailBuildException("サポートさ�?ていない文字コードが指定さ�?ました。", e);
217 		} catch (MessagingException e) {
218 			throw new MailBuildException("MimeMessageの生成に失敗しました。", e);
219 		}
220 		// 送信
221 		send(message);
222 	}
223 
224 	/***
225 	 * 指定さ�?たMailにセットさ�?たReturn-Pathを設定して、メー�?を送信します。
226 	 * 同�?メソッドです。
227 	 * 
228 	 * @param mail
229 	 * @throws MailException
230 	 */
231 	private synchronized void sendMailWithReturnPath(Mail mail) throws MailException {
232 		putOnReturnPath(mail.getReturnPath().getAddress());
233 
234 		sendMail(mail);
235 
236 		releaseReturnPath(true);
237 	}
238 
239 	/***
240 	 * 新しいMimeMessageオブジェクトを生成します。
241 	 * 
242 	 * @return 新しいMimeMessageオブジェクト
243 	 */
244 	public MimeMessage createMimeMessage() {
245 		if (messageId == null) {
246 			return new MimeMessage(session);
247 		}
248 		return new OMLMimeMessage(session, messageId);
249 	}
250 
251 	/***
252 	 * @return Returns the session.
253 	 */
254 	protected Session getSession() {
255 		return session;
256 	}
257 
258 	/***
259 	 * エンコーディングに使用す�?文字コードを返します。
260 	 * 
261 	 * @return エンコーディングに使用す�?文字コード
262 	 */
263 	public String getCharset() {
264 		return charset;
265 	}
266 
267 	/***
268 	 * メー�?の�?名や本文のエンコーディングに使用す�?文字コードを指定します。
269 	 * デフォ�?トは ISO-2022-JP です。
270 	 * <p>
271 	 * �?本�?環境で利用す�?�?合は通�?変更す�?必要はありません。
272 	 * 
273 	 * @param charset エンコーディングに使用す�?文字コード
274 	 */
275 	public void setCharset(String charset) {
276 		this.charset = charset;
277 	}
278 
279 	/***
280 	 * @return Returns the host.
281 	 */
282 	public String getHost() {
283 		return host;
284 	}
285 
286 	/***
287 	 * SMTPサーバのホスト名、またはIPアド�?スをセットします。
288 	 * デフォ�?トは localhost です。
289 	 * 
290 	 * @param host SMTPサーバのホスト名、またはIPアド�?ス
291 	 */
292 	public void setHost(String host) {
293 		this.host = host;
294 	}
295 
296 	/***
297 	 * @return SMTPサーバ認証パス�?ード
298 	 */
299 	public String getPassword() {
300 		return password;
301 	}
302 
303 	/***
304 	 * SMTPサーバの接続認証が必要な�?合にパス�?ードをセットします。
305 	 * 
306 	 * @param password SMTPサーバ認証パス�?ード
307 	 */
308 	public void setPassword(String password) {
309 		this.password = password;
310 	}
311 
312 	/***
313 	 * @return SMTPサーバのポート番�?
314 	 */
315 	public int getPort() {
316 		return port;
317 	}
318 
319 	/***
320 	 * SMTPサーバのポート番号をセットします。
321 	 * 
322 	 * @param port SMTPサーバのポート番�?
323 	 */
324 	public void setPort(int port) {
325 		this.port = port;
326 	}
327 
328 	/***
329 	 * @return Returns the protocol.
330 	 */
331 	public String getProtocol() {
332 		return protocol;
333 	}
334 
335 	/***
336 	 * @param protocol The protocol to set.
337 	 */
338 	public void setProtocol(String protocol) {
339 		this.protocol = protocol;
340 	}
341 
342 	/***
343 	 * @return Return-Pathアド�?ス
344 	 */
345 	public String getReturnPath() {
346 		return returnPath;
347 	}
348 
349 	/***
350 	 * Return-Pathアド�?スをセットします。
351 	 * <p>
352 	 * 送信す�?Mailインスタンスに指定さ�?たFromアド�?ス以外のアド�?スをReturn-Pathとしたい�?合に使用します。
353 	 * ここでセットさ�?たReturn-Pathより、Mailインスタンスにセットさ�?たReturn-Pathが優先さ�?ます。
354 	 * 
355 	 * @param returnPath Return-Pathアド�?ス
356 	 */
357 	public void setReturnPath(String returnPath) {
358 		this.returnPath = returnPath;
359 	}
360 
361 	/***
362 	 * @return SMTPサーバ認証ユーザ名
363 	 */
364 	public String getUsername() {
365 		return username;
366 	}
367 
368 	/***
369 	 * SMTPサーバの接続認証が必要な�?合にユーザ名をセットします。
370 	 * 
371 	 * @param username SMTPサーバ認証ユーザ名
372 	 */
373 	public void setUsername(String username) {
374 		this.username = username;
375 	}
376 
377 	/***
378 	 * 生成さ�?�?MimeMessageに付けら�?�?Message-Idヘッダのドメイン部分を指定します。<br>
379 	 * 指定さ�?ない�?�?(nullや空文字列の�?�?)は、JavaMailがMessage-Idヘッダを生成します。
380 	 * JavaMailが生成す�?「JavaMail.実行ユーザ名@ホスト名」のMessage-Idを避けたい�?合に、このメソッドを使用します。
381 	 * <p>
382 	 * messageIdプ��叢ティがセットさ�?てい�?�?合、Mailから生成さ�?�?MimeMessageのMessage-Idには
383 	 * <code>タイムスタンプ + ランダムに生成さ�?�?16桁の数値 + ここでセットさ�?た値</code>
384 	 * が使用さ�?ます。
385 	 * <p>
386 	 * 生成さ�?�?Message-Idの例。 (実際の数値部分は送信メー�?毎に変�?ります)<ul>
387 	 * <li>messageIdに'example.com'を指定した�?合・・・1095714924963.5619528074501343@example.com</li>
388 	 * <li>messageIdに'@example.com'を指定した�?合・・・1095714924963.5619528074501343@example.com (上と同じ)</li>
389 	 * <li>messageIdに'OML@example.com'を指定した�?合・・・1095714924963.5619528074501343.OML@example.com</li>
390 	 * <li>messageIdに'.OML@example.com'を指定した�?合・・・1095714924963.5619528074501343.OML@example.com (上と同じ)</li>
391 	 * </ul>
392 	 * <p>
393 	 * <strong>�?:</strong> このMessage-Idは<code>send(Mail)</code>か<code>send(Mail[])</code>メソッドが呼びだ�?た�?にのみ有効です。MimeMessageを直接送信す�?�?合には適用さ�?ません。
394 	 * 
395 	 * @param messageId メー�?に付けら�?�?Message-Idヘッダのドメイン部分
396 	 * @throws IllegalArgumentException @を複数含んだ文字列を指定した�?�?
397 	 */
398 	public void setMessageId(String messageId) {
399 		if (messageId == null || messageId.length() < 1) {
400 			return;
401 		}
402 
403 		String[] parts = messageId.split("@");
404 		if (parts.length > 2) {
405 			throw new IllegalArgumentException("messageIdプ��叢ティに'@'を複数含むことはできません。[" + messageId
406 					+ "]");
407 		}
408 
409 		this.messageId = messageId;
410 	}
411 }