OSDN Git Service

CVS最新版の全ファイルを追加
[spring-ext/ozacc-mail.git] / src / java / com / ozacc / mail / impl / SendMailProImpl.java
1 package com.ozacc.mail.impl;\r
2 \r
3 import java.io.UnsupportedEncodingException;\r
4 import java.util.Date;\r
5 import java.util.Properties;\r
6 \r
7 import javax.mail.Address;\r
8 import javax.mail.AuthenticationFailedException;\r
9 import javax.mail.MessagingException;\r
10 import javax.mail.Session;\r
11 import javax.mail.Transport;\r
12 import javax.mail.internet.MimeMessage;\r
13 \r
14 import org.apache.commons.logging.Log;\r
15 import org.apache.commons.logging.LogFactory;\r
16 \r
17 import com.ozacc.mail.Mail;\r
18 import com.ozacc.mail.MailAuthenticationException;\r
19 import com.ozacc.mail.MailBuildException;\r
20 import com.ozacc.mail.MailException;\r
21 import com.ozacc.mail.MailSendException;\r
22 import com.ozacc.mail.NotConnectedException;\r
23 import com.ozacc.mail.SendMailPro;\r
24 \r
25 /**\r
26  * SendMailProインターフェースの実装クラス。\r
27  * \r
28  * @since 1.0\r
29  * @author Tomohiro Otsuka\r
30  * @version $Id: SendMailProImpl.java,v 1.4.2.5 2006/08/07 13:45:22 otsuka Exp $\r
31  */\r
32 public class SendMailProImpl implements SendMailPro {\r
33 \r
34         /** smtp */\r
35         public static final String DEFAULT_PROTOCOL = "smtp";\r
36 \r
37         /** -1 */\r
38         public static final int DEFAULT_PORT = -1;\r
39 \r
40         /** localhost */\r
41         public static final String DEFAULT_HOST = "localhost";\r
42 \r
43         /** ISO-2022-JP */\r
44         public static final String JIS_CHARSET = "ISO-2022-JP";\r
45 \r
46         private static final String RETURN_PATH_KEY = "mail.smtp.from";\r
47 \r
48         private static Log log = LogFactory.getLog(SendMailProImpl.class);\r
49 \r
50         /** 接続タイムアウト */\r
51         private static final int DEFAULT_CONNECTION_TIMEOUT = 5000;\r
52 \r
53         /** 読込タイムアウト */\r
54         private static final int DEFAULT_READ_TIMEOUT = 5000;\r
55 \r
56         private String protocol = DEFAULT_PROTOCOL;\r
57 \r
58         private String host = DEFAULT_HOST;\r
59 \r
60         private int port = DEFAULT_PORT;\r
61 \r
62         private String username;\r
63 \r
64         private String password;\r
65 \r
66         private String charset = JIS_CHARSET;\r
67 \r
68         private String returnPath;\r
69 \r
70         private Session session;\r
71 \r
72         private Transport transport;\r
73 \r
74         private boolean connected;\r
75 \r
76         private String messageId;\r
77 \r
78         private int connectionTimeout = DEFAULT_CONNECTION_TIMEOUT;\r
79 \r
80         private int readTimeout = DEFAULT_READ_TIMEOUT;\r
81 \r
82         /**\r
83          * コンストラクタ。\r
84          */\r
85         public SendMailProImpl() {}\r
86 \r
87         /**\r
88          * コンストラクタ。使用するSMTPサーバを指定します。\r
89          * \r
90          * @param host SMTPサーバのホスト名、またはIPアドレス\r
91          */\r
92         public SendMailProImpl(String host) {\r
93                 this();\r
94                 setHost(host);\r
95         }\r
96 \r
97         /**\r
98          * @see com.ozacc.mail.SendMailPro#connect()\r
99          */\r
100         public synchronized void connect() throws MailException {\r
101                 if (session == null) {\r
102                         initSession();\r
103                 }\r
104 \r
105                 // グローバルReturn-Pathの設定\r
106                 putOnReturnPath(this.returnPath);\r
107 \r
108                 try {\r
109                         // SMTPサーバに接続\r
110                         log.debug("SMTPサーバ[" + host + "]に接続します。");\r
111 \r
112                         transport = session.getTransport(protocol);\r
113                         transport.connect(host, port, username, password);\r
114                 } catch (AuthenticationFailedException ex) {\r
115                         log.error("SMTPサーバ[" + host + "]への接続認証に失敗しました。", ex);\r
116                         throw new MailAuthenticationException(ex);\r
117                 } catch (MessagingException ex) {\r
118                         log.error("SMTPサーバ[" + host + "]への接続に失敗しました。", ex);\r
119                         throw new MailSendException("SMTPサーバ[" + host + "]への接続に失敗しました。", ex);\r
120                 }\r
121 \r
122                 log.debug("SMTPサーバ[" + host + "]に接続しました。");\r
123 \r
124                 connected = true;\r
125         }\r
126 \r
127         /**\r
128          * Sessionの初期化を行います。\r
129          * タイムアウト値を設定したPropertiesをセットします。\r
130          */\r
131         private void initSession() {\r
132                 Properties prop = new Properties();\r
133                 // タイムアウトの設定\r
134                 prop.put("mail.smtp.connectiontimeout", String.valueOf(connectionTimeout));\r
135                 prop.put("mail.smtp.timeout", String.valueOf(readTimeout));\r
136                 //      mail.smtp.authプロパティの設定\r
137                 if (username != null && !"".equals(username) && password != null && !"".equals(password)) {\r
138                         prop.put("mail.smtp.auth", "true");\r
139                 }\r
140                 session = Session.getInstance(prop);\r
141         }\r
142 \r
143         /**\r
144          * @see com.ozacc.mail.SendMailPro#disconnect()\r
145          */\r
146         public synchronized void disconnect() throws MailException {\r
147                 if (connected) {\r
148                         try {\r
149                                 log.debug("SMTPサーバ[" + host + "]との接続を切断します。");\r
150 \r
151                                 // SMTPサーバとの接続を切断\r
152                                 transport.close();\r
153                                 connected = false;\r
154 \r
155                                 log.debug("SMTPサーバ[" + host + "]との接続を切断しました。");\r
156                         } catch (MessagingException ex) {\r
157                                 log.error("SMTPサーバ[" + host + "]との接続切断に失敗しました。", ex);\r
158                                 throw new MailException("SMTPサーバ[" + host + "]との接続切断に失敗しました。");\r
159                         } finally {\r
160                                 // グローバルReturn-Pathの解除\r
161                                 releaseReturnPath(false);\r
162                         }\r
163                 } else {\r
164                         log.warn("SMTPサーバ[" + host + "]との接続が確立されていない状態で、接続の切断がリクエストされました。");\r
165                 }\r
166         }\r
167 \r
168         /**\r
169          * ReturnPathをセットします。\r
170          * \r
171          * @param returnPath\r
172          */\r
173         private void putOnReturnPath(String returnPath) {\r
174                 if (returnPath != null) {\r
175                         session.getProperties().put(RETURN_PATH_KEY, returnPath);\r
176                         log.debug("Return-Path[" + returnPath + "]を設定しました。");\r
177                 }\r
178         }\r
179 \r
180         /**\r
181          * ReturnPathの設定をクリアします。\r
182          * <p>\r
183          * setGlobalReturnPathAgainがtrueに指定されている場合、一旦Return-Path設定をクリアした後に、\r
184          * グローバルなReturn-Path(setReturnPath()メソッドで、このインスタンスにセットされたReturn-Pathアドレス)を設定します。\r
185          * グローバルなReturn-PathがセットされていなければReturn-Pathはクリアされたままになります。\r
186          * <p>\r
187          * クリアされた状態でsend()メソッドが実行されると、Fromの値がReturn-Pathに使用されます。\r
188          * \r
189          * @param setGlobalReturnPathAgain Return-Path設定をクリアした後、再度グローバルなReturn-Pathをセットする場合 true\r
190          */\r
191         private void releaseReturnPath(boolean setGlobalReturnPathAgain) {\r
192                 session.getProperties().remove(RETURN_PATH_KEY);\r
193                 log.debug("Return-Path設定をクリアしました。");\r
194 \r
195                 if (setGlobalReturnPathAgain && this.returnPath != null) {\r
196                         putOnReturnPath(this.returnPath);\r
197                 }\r
198         }\r
199 \r
200         /**\r
201          * @see com.ozacc.mail.SendMailPro#send(javax.mail.internet.MimeMessage)\r
202          */\r
203         public void send(MimeMessage mimeMessage) throws MailException {\r
204                 Address[] addresses;\r
205                 try {\r
206                         addresses = mimeMessage.getAllRecipients();\r
207                 } catch (MessagingException ex) {\r
208                         log.error("メールの送信に失敗しました。", ex);\r
209                         throw new MailSendException("メールの送信に失敗しました。", ex);\r
210                 }\r
211                 processSend(mimeMessage, addresses);\r
212         }\r
213 \r
214         /**\r
215          * @param mimeMessage \r
216          */\r
217         private void processSend(MimeMessage mimeMessage, Address[] addresses) {\r
218                 if (!connected) {\r
219                         log.error("SMTPサーバへの接続が確立されていません。");\r
220                         throw new NotConnectedException("SMTPサーバへの接続が確立されていません。");\r
221                 }\r
222 \r
223                 try {\r
224                         // 送信日時をセット\r
225                         mimeMessage.setSentDate(new Date());\r
226                         mimeMessage.saveChanges();\r
227                         // 送信\r
228                         log.debug("メールを送信します。");\r
229                         transport.sendMessage(mimeMessage, addresses);\r
230                         log.debug("メールを送信しました。");\r
231                 } catch (MessagingException ex) {\r
232                         log.error("メールの送信に失敗しました。", ex);\r
233                         throw new MailSendException("メールの送信に失敗しました。", ex);\r
234                 }\r
235         }\r
236 \r
237         /**\r
238          * @see com.ozacc.mail.SendMailPro#send(com.ozacc.mail.Mail)\r
239          */\r
240         public void send(Mail mail) throws MailException {\r
241                 if (mail.getReturnPath() != null) {\r
242                         sendMailWithReturnPath(mail);\r
243                 } else {\r
244                         sendMail(mail);\r
245                 }\r
246         }\r
247 \r
248         /**\r
249          * 指定されたMailからMimeMessageを生成し、send(MimeMessage)メソッドに渡します。\r
250          * \r
251          * @param mail\r
252          * @throws MailException\r
253          */\r
254         private void sendMail(Mail mail) throws MailException {\r
255                 // MimeMessageの生成\r
256                 MimeMessage message = createMimeMessage();\r
257                 if (isMessageIdCustomized()) {\r
258                         mail.addHeader("Message-ID", ((OMLMimeMessage)message).getMessageId());\r
259                 }\r
260                 MimeMessageBuilder builder = new MimeMessageBuilder(message, charset);\r
261                 try {\r
262                         builder.buildMimeMessage(mail);\r
263                 } catch (UnsupportedEncodingException e) {\r
264                         throw new MailBuildException("サポートされていない文字コードが指定されました。", e);\r
265                 } catch (MessagingException e) {\r
266                         throw new MailBuildException("MimeMessageの生成に失敗しました。", e);\r
267                 }\r
268                 // 送信\r
269                 if (mail.getEnvelopeTo().length > 0) {\r
270                         log.debug("メールはenvelope-toアドレスに送信されます。");\r
271                         processSend(message, mail.getEnvelopeTo());\r
272                 } else {\r
273                         send(message);\r
274                 }\r
275         }\r
276 \r
277         /**\r
278          * 指定されたMailにセットされたReturn-Pathを設定して、メールを送信します。\r
279          * 同期メソッドです。\r
280          * \r
281          * @param mail\r
282          * @throws MailException\r
283          */\r
284         private synchronized void sendMailWithReturnPath(Mail mail) throws MailException {\r
285                 putOnReturnPath(mail.getReturnPath().getAddress());\r
286 \r
287                 sendMail(mail);\r
288 \r
289                 releaseReturnPath(true);\r
290         }\r
291 \r
292         /**\r
293          * 新しいMimeMessageオブジェクトを生成します。\r
294          * \r
295          * @return 新しいMimeMessageオブジェクト\r
296          */\r
297         public MimeMessage createMimeMessage() {\r
298                 if (isMessageIdCustomized()) {\r
299                         return new OMLMimeMessage(session, messageId);\r
300                 }\r
301                 return new MimeMessage(session);\r
302         }\r
303 \r
304         /**\r
305          * Message-Idヘッダのドメイン部分を独自にセットしているかどうか判定します。\r
306          * \r
307          * @return Message-Idヘッダのドメイン部分を独自にセットしている場合 true\r
308          */\r
309         private boolean isMessageIdCustomized() {\r
310                 return messageId != null;\r
311         }\r
312 \r
313         /**\r
314          * @return Sessionインスタンス\r
315          */\r
316         protected Session getSession() {\r
317                 return session;\r
318         }\r
319 \r
320         /**\r
321          * エンコーディングに使用する文字コードを返します。\r
322          * \r
323          * @return エンコーディングに使用する文字コード\r
324          */\r
325         public String getCharset() {\r
326                 return charset;\r
327         }\r
328 \r
329         /**\r
330          * メールの件名や本文のエンコーディングに使用する文字コードを指定します。\r
331          * デフォルトは ISO-2022-JP です。\r
332          * <p>\r
333          * 日本語環境で利用する場合は通常変更する必要はありません。\r
334          * \r
335          * @param charset エンコーディングに使用する文字コード\r
336          */\r
337         public void setCharset(String charset) {\r
338                 this.charset = charset;\r
339         }\r
340 \r
341         /**\r
342          * @return Returns the host.\r
343          */\r
344         public String getHost() {\r
345                 return host;\r
346         }\r
347 \r
348         /**\r
349          * SMTPサーバのホスト名、またはIPアドレスをセットします。\r
350          * デフォルトは localhost です。\r
351          * \r
352          * @param host SMTPサーバのホスト名、またはIPアドレス\r
353          */\r
354         public void setHost(String host) {\r
355                 this.host = host;\r
356         }\r
357 \r
358         /**\r
359          * @return SMTPサーバ認証パスワード\r
360          */\r
361         public String getPassword() {\r
362                 return password;\r
363         }\r
364 \r
365         /**\r
366          * SMTPサーバの接続認証が必要な場合にパスワードをセットします。\r
367          * \r
368          * @param password SMTPサーバ認証パスワード\r
369          */\r
370         public void setPassword(String password) {\r
371                 this.password = password;\r
372         }\r
373 \r
374         /**\r
375          * @return SMTPサーバのポート番号\r
376          */\r
377         public int getPort() {\r
378                 return port;\r
379         }\r
380 \r
381         /**\r
382          * SMTPサーバのポート番号をセットします。\r
383          * \r
384          * @param port SMTPサーバのポート番号\r
385          */\r
386         public void setPort(int port) {\r
387                 this.port = port;\r
388         }\r
389 \r
390         /**\r
391          * プロトコルを返します。\r
392          * \r
393          * @return プロトコル\r
394          */\r
395         public String getProtocol() {\r
396                 return protocol;\r
397         }\r
398 \r
399         /**\r
400          * プロトコルをセットします。デフォルトは「smtp」。\r
401          * \r
402          * @param protocol プロトコル\r
403          */\r
404         public void setProtocol(String protocol) {\r
405                 this.protocol = protocol;\r
406         }\r
407 \r
408         /**\r
409          * @return Return-Pathアドレス\r
410          */\r
411         public String getReturnPath() {\r
412                 return returnPath;\r
413         }\r
414 \r
415         /**\r
416          * Return-Pathアドレスをセットします。\r
417          * <p>\r
418          * 送信するMailインスタンスに指定されたFromアドレス以外のアドレスをReturn-Pathとしたい場合に使用します。\r
419          * ここでセットされたReturn-Pathより、MailインスタンスにセットされたReturn-Pathが優先されます。\r
420          * \r
421          * @param returnPath Return-Pathアドレス\r
422          */\r
423         public void setReturnPath(String returnPath) {\r
424                 this.returnPath = returnPath;\r
425         }\r
426 \r
427         /**\r
428          * @return SMTPサーバ認証ユーザ名\r
429          */\r
430         public String getUsername() {\r
431                 return username;\r
432         }\r
433 \r
434         /**\r
435          * SMTPサーバの接続認証が必要な場合にユーザ名をセットします。\r
436          * \r
437          * @param username SMTPサーバ認証ユーザ名\r
438          */\r
439         public void setUsername(String username) {\r
440                 this.username = username;\r
441         }\r
442 \r
443         /**\r
444          * 生成されるMimeMessageに付けられるMessage-Idヘッダのドメイン部分を指定します。<br>\r
445          * 指定されない場合(nullや空文字列の場合)は、JavaMailがMessage-Idヘッダを生成します。\r
446          * JavaMailが生成する「JavaMail.実行ユーザ名@ホスト名」のMessage-Idを避けたい場合に、このメソッドを使用します。\r
447          * <p>\r
448          * messageIdプロパティがセットされている場合、Mailから生成されるMimeMessageのMessage-Idには\r
449          * <code>タイムスタンプ + ランダムに生成される16桁の数値 + ここでセットされた値</code>\r
450          * が使用されます。\r
451          * <p>\r
452          * 生成されるMessage-Idの例。 (実際の数値部分は送信メール毎に変わります)<ul>\r
453          * <li>messageIdに'example.com'を指定した場合・・・1095714924963.5619528074501343@example.com</li>\r
454          * <li>messageIdに'@example.com'を指定した場合・・・1095714924963.5619528074501343@example.com (上と同じ)</li>\r
455          * <li>messageIdに'OML@example.com'を指定した場合・・・1095714924963.5619528074501343.OML@example.com</li>\r
456          * <li>messageIdに'.OML@example.com'を指定した場合・・・1095714924963.5619528074501343.OML@example.com (上と同じ)</li>\r
457          * </ul>\r
458          * <p>\r
459          * <strong>注:</strong> このMessage-Idは<code>send(Mail)</code>か<code>send(Mail[])</code>メソッドが呼びだれた時にのみ有効です。MimeMessageを直接送信する場合には適用されません。\r
460          * \r
461          * @param messageId メールに付けられるMessage-Idヘッダのドメイン部分\r
462          * @throws IllegalArgumentException @を複数含んだ文字列を指定した場合\r
463          */\r
464         public void setMessageId(String messageId) {\r
465                 if (messageId == null || messageId.length() < 1) {\r
466                         return;\r
467                 }\r
468                 String[] parts = messageId.split("@");\r
469                 if (parts.length > 2) {\r
470                         throw new IllegalArgumentException("messageIdプロパティに'@'を複数含むことはできません。[" + messageId\r
471                                         + "]");\r
472                 }\r
473                 this.messageId = messageId;\r
474         }\r
475 \r
476         /**\r
477          * SMTPサーバとの接続タイムアウトをセットします。\r
478          * 単位はミリ秒。デフォルトは5,000ミリ秒(5秒)です。\r
479          * <p>\r
480          * -1を指定すると無限大になりますが、お薦めしません。\r
481          * \r
482          * @since 1.1.4\r
483          * @param connectionTimeout SMTPサーバとの接続タイムアウト\r
484          */\r
485         public void setConnectionTimeout(int connectionTimeout) {\r
486                 this.connectionTimeout = connectionTimeout;\r
487         }\r
488 \r
489         /**\r
490          * SMTPサーバへの送受信時のタイムアウトをセットします。\r
491          * 単位はミリ秒。デフォルトは5,000ミリ秒(5秒)です。\r
492          * <p>\r
493          * -1を指定すると無限大になりますが、お薦めしません。\r
494          * \r
495          * @since 1.1.4\r
496          * @param readTimeout SMTPサーバへの送受信時のタイムアウト\r
497          */\r
498         public void setReadTimeout(int readTimeout) {\r
499                 this.readTimeout = readTimeout;\r
500         }\r
501 }