OSDN Git Service

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