View Javadoc

1   package com.ozacc.mail.impl;
2   
3   import java.io.UnsupportedEncodingException;
4   import java.util.Iterator;
5   import java.util.Map;
6   
7   import javax.activation.DataHandler;
8   import javax.activation.DataSource;
9   import javax.mail.MessagingException;
10  import javax.mail.internet.InternetAddress;
11  import javax.mail.internet.MimeBodyPart;
12  import javax.mail.internet.MimeMessage;
13  import javax.mail.internet.MimeMultipart;
14  import javax.mail.internet.MimePart;
15  import javax.mail.internet.MimeUtility;
16  
17  import com.ozacc.mail.Mail;
18  
19  /***
20   * MimeMessageインスタンスを生成するクラス。Mail一通毎に生成されます。
21   * 
22   * @since 1.0
23   * @author Tomohiro Otsuka
24   * @version $Id: MimeMessageBuilder.java,v 1.11.2.2 2007/03/30 13:03:44 otsuka Exp $
25   */
26  public class MimeMessageBuilder {
27  
28  	private MimeMessage mimeMessage;
29  
30  	private String charset = Mail.JIS_CHARSET;
31  
32  	private boolean hasRecipient = false;
33  
34  	/***
35  	 * コンストラクタ。
36  	 * デフォルトの文字コード ISO-2022-JP がエンコーディングに使用されます。
37  	 * 
38  	 * @param mimeMessage
39  	 */
40  	public MimeMessageBuilder(MimeMessage mimeMessage) {
41  		this.mimeMessage = mimeMessage;
42  	}
43  
44  	/***
45  	 * コンストラクタ。
46  	 * 本文や件名のエンコーディングに使用する文字コードを指定します。
47  	 * 
48  	 * @param mimeMessage
49  	 * @param charset エンコーディングに使用する文字コード
50  	 */
51  	public MimeMessageBuilder(MimeMessage mimeMessage, String charset) {
52  		this.mimeMessage = mimeMessage;
53  		this.charset = charset;
54  	}
55  
56  	/***
57  	 * コンストラクタの引数で渡されたMimeMessageをそのまま返します。
58  	 * 
59  	 * @return MimeMessage
60  	 */
61  	public MimeMessage getMimeMessage() {
62  		return this.mimeMessage;
63  	}
64  
65  	/***
66  	 * 指定されたメールからMimeMessageを生成します。
67  	 * 
68  	 * @param mail MimeMessageのソースとなるMail
69  	 * @throws MessagingException
70  	 * @throws UnsupportedEncodingException
71  	 */
72  	public void buildMimeMessage(Mail mail) throws UnsupportedEncodingException, MessagingException {
73  		setCharset(mail);
74  
75  		setTo(mail);
76  		setCc(mail);
77  		setBcc(mail);
78  		// 宛先の指定がない場合エラー
79  		if (!hasRecipient) {
80  			throw new MessagingException("宛先の指定がありません。To、Cc、Bccのいずれか一つは指定する必要があります。");
81  		}
82  		setFrom(mail);
83  		setSubject(mail);
84  		setReplyTo(mail);
85  		setXHeaders(mail);
86  		setImportance(mail);
87  
88  		if (mail.isMultipartMail()) {
89  
90  			if (!mail.isFileAttached() && mail.isHtmlMail()) { // Plain text, HTML
91  
92  				if (mail.getText() != null && mail.getText().length() > 0) { // Plain text, HTML
93  
94  					MimeMultipart textAndHtmlMultipart = new MimeMultipart("alternative");
95  					setPlainText(mail, textAndHtmlMultipart);
96  					setHtmlText(mail, textAndHtmlMultipart);
97  					this.mimeMessage.setContent(textAndHtmlMultipart);
98  
99  				} else { // HTML Only マルチパートは使用しない
100 
101 					setHtmlText(mail.getHtmlText(), this.mimeMessage);
102 
103 				}
104 
105 			} else if (mail.isFileAttached() && mail.isHtmlMail()) { // Plain text, HMTL, File
106 
107 				MimeMultipart textAndHtmlMultipart = new MimeMultipart("alternative");
108 				setPlainText(mail, textAndHtmlMultipart);
109 				setHtmlText(mail, textAndHtmlMultipart);
110 
111 				MimeMultipart containingMultipart = new MimeMultipart();
112 				MimeBodyPart textBodyPart = createMimeBodyPart(containingMultipart);
113 				textBodyPart.setContent(textAndHtmlMultipart);
114 				setAttachmentFiles(mail, containingMultipart);
115 
116 				this.mimeMessage.setContent(containingMultipart);
117 
118 			} else if (mail.isFileAttached() && !mail.isHtmlMail()) { // Plain text, File
119 
120 				MimeMultipart textAndFileMultipart = new MimeMultipart();
121 				setPlainText(mail, textAndFileMultipart);
122 				setAttachmentFiles(mail, textAndFileMultipart);
123 				this.mimeMessage.setContent(textAndFileMultipart);
124 
125 			} else { // Plain text only マルチパートは使用しない
126 
127 				setText(mail.getText(), this.mimeMessage);
128 
129 			}
130 
131 		} else {
132 
133 			setText(mail.getText(), this.mimeMessage);
134 
135 		}
136 
137 	}
138 
139 	/***
140 	 * メールに使用するcharsetを決定します。
141 	 * Mail#charsetが設定されている場合、その値が優先されます。
142 	 * 
143 	 * @since 1.2.1
144 	 * @param mail
145 	 */
146 	private void setCharset(Mail mail) {
147 		if (mail.getCharset() != null && !"".equals(mail.getCharset())) {
148 			charset = mail.getCharset();
149 		}
150 	}
151 
152 	/***
153 	 * 
154 	 * @since 1.1
155 	 * 
156 	 * @param mail
157 	 * @param mimeMultipart
158 	 * @throws MessagingException
159 	 * @throws UnsupportedEncodingException 
160 	 */
161 	private void setAttachmentFiles(Mail mail, MimeMultipart mimeMultipart)
162 																			throws MessagingException,
163 																			UnsupportedEncodingException {
164 		Mail.AttachmentFile[] files = mail.getAttachmentFiles();
165 		for (int i = 0; i < files.length; i++) {
166 			MimeBodyPart bodyPart = createMimeBodyPart(mimeMultipart);
167 			Mail.AttachmentFile attachmentFile = files[i];
168 			addAttachment(attachmentFile.getName(), attachmentFile.getDataSource(), bodyPart);
169 		}
170 	}
171 
172 	/***
173 	 * 
174 	 * @since 1.1
175 	 * 
176 	 * @param mail
177 	 * @param mimeMultipart
178 	 * @throws MessagingException 
179 	 */
180 	private void setHtmlText(Mail mail, MimeMultipart mimeMultipart) throws MessagingException {
181 		if (mail.isHtmlMail()) {
182 			MimeBodyPart bodyPart = createMimeBodyPart(mimeMultipart);
183 			setHtmlText(mail.getHtmlText(), bodyPart);
184 		}
185 	}
186 
187 	/***
188 	 * 
189 	 * @since 1.1
190 	 * 
191 	 * @param mail
192 	 * @param mimeMultipart
193 	 * @throws MessagingException 
194 	 */
195 	private void setPlainText(Mail mail, MimeMultipart mimeMultipart) throws MessagingException {
196 		if (mail.getText() != null && mail.getText().length() > 0) {
197 			MimeBodyPart bodyPart = createMimeBodyPart(mimeMultipart);
198 			setText(mail.getText(), bodyPart);
199 		}
200 	}
201 
202 	/***
203 	 * 新しいMimeBodyPartインスタンスを生成し、指定されたMimeMultipartに登録します。
204 	 * 
205 	 * このメソッドはマルチパートメール生成時にのみ呼び出すことができます。
206 	 * プレーンテキストメール生成時には、mimeMulipartがnullなので、
207 	 * NullPointerExceptionがスローされます。
208 	 * 
209 	 * @since 1.1
210 	 * 
211 	 * @param mm
212 	 * @return 生成されたMimeBodyPart
213 	 * @throws MessagingException 
214 	 */
215 	private MimeBodyPart createMimeBodyPart(MimeMultipart mm) throws MessagingException {
216 		MimeBodyPart bodyPart = new MimeBodyPart();
217 		mm.addBodyPart(bodyPart);
218 		return bodyPart;
219 	}
220 
221 	/***
222 	 * @since 1.1
223 	 * 
224 	 * @param htmlText
225 	 * @param mimePart 
226 	 * @throws MessagingException
227 	 */
228 	private void setHtmlText(final String htmlText, MimePart mimePart) throws MessagingException {
229 		if (charset != null) {
230 			mimePart.setContent(htmlText, "text/html; charset=" + charset);
231 		} else {
232 			mimePart.setContent(htmlText, "text/html");
233 		}
234 		setContentTransferEncoding(mimePart);
235 	}
236 
237 	/***
238 	 * @param mail 
239 	 * @throws MessagingException
240 	 */
241 	private void setXHeaders(Mail mail) throws MessagingException {
242 		Map headers = mail.getHeaders();
243 		if (headers == null) {
244 			return;
245 		}
246 
247 		Iterator itr = headers.keySet().iterator();
248 		while (itr.hasNext()) {
249 			String key = (String)itr.next();
250 			String value = (String)headers.get(key);
251 			mimeMessage.setHeader(key, value);
252 		}
253 	}
254 
255 	/***
256 	 * @param mail 
257 	 * @throws MessagingException
258 	 */
259 	private void setImportance(Mail mail) throws MessagingException {
260 		if (mail.getImportance() != null) {
261 			mimeMessage.setHeader("Importance", mail.getImportance());
262 
263 			int level = 3;
264 			if (Mail.Importance.HIGH.equals(mail.getImportance())) {
265 				level = 1;
266 			} else if (Mail.Importance.LOW.equals(mail.getImportance())) {
267 				level = 5;
268 			}
269 			mimeMessage.setHeader("X-Priority", String.valueOf(level));
270 		}
271 	}
272 
273 	/***
274 	 * @param mail 
275 	 * @throws MessagingException
276 	 * @throws UnsupportedEncodingException 
277 	 */
278 	private void setReplyTo(Mail mail) throws MessagingException, UnsupportedEncodingException {
279 		if (mail.getReplyTo() != null) {
280 			mimeMessage.setReplyTo(new InternetAddress[] { convertCharset(mail.getReplyTo()) });
281 		}
282 	}
283 
284 	/***
285 	 * @param mail 
286 	 * @throws MessagingException
287 	 * @throws UnsupportedEncodingException 
288 	 */
289 	private void setBcc(Mail mail) throws MessagingException, UnsupportedEncodingException {
290 		if (mail.getBcc().length > 0) {
291 			mimeMessage.setRecipients(MimeMessage.RecipientType.BCC, convertCharset(mail.getBcc()));
292 			hasRecipient = true;
293 		}
294 	}
295 
296 	/***
297 	 * @param mail 
298 	 * @throws MessagingException
299 	 * @throws UnsupportedEncodingException 
300 	 */
301 	private void setCc(Mail mail) throws MessagingException, UnsupportedEncodingException {
302 		if (mail.getCc().length > 0) {
303 			mimeMessage.setRecipients(MimeMessage.RecipientType.CC, convertCharset(mail.getCc()));
304 			hasRecipient = true;
305 		}
306 	}
307 
308 	/***
309 	 * @param mail 
310 	 * @throws MessagingException
311 	 * @throws UnsupportedEncodingException 
312 	 */
313 	private void setTo(Mail mail) throws MessagingException, UnsupportedEncodingException {
314 		if (mail.getTo().length > 0) {
315 			mimeMessage.setRecipients(MimeMessage.RecipientType.TO, convertCharset(mail.getTo()));
316 			hasRecipient = true;
317 		}
318 	}
319 
320 	/***
321 	 * 本文をセット。
322 	 * <p>
323 	 * NOTE: 本文の最後に改行がないとMozilla系のメーラーで最終行の日本語が文字化けしてしまう為、
324 	 * message.setTextの引数で最後に\nを追加している。
325 	 * 
326 	 * @since 1.1
327 	 * 
328 	 * @param text 本文
329 	 * @param mimePart 本文をセットするMimePart 
330 	 * @throws MessagingException
331 	 */
332 	private void setText(String text, MimePart mimePart) throws MessagingException {
333 		if (charset != null) {
334 			if (charset.equalsIgnoreCase(Mail.JIS_CHARSET)) {
335 				// Cp932クラスを使用して、怪しい記号を強制的にJIS変換
336 				mimePart.setText(Cp932.toJIS(text) + "\n", charset);
337 			} else {
338 				mimePart.setText(text + "\n", charset);
339 			}
340 		} else {
341 			mimePart.setText(text + "\n");
342 		}
343 		setContentTransferEncoding(mimePart);
344 	}
345 
346 	/***
347 	 * charsetに応じてContent-Trnasfer-Encodingを設定します。
348 	 * が、UTF-8の時に8bitになること以外分かりません。。。
349 	 * 
350 	 * @since 1.2.1
351 	 * @param mimePart
352 	 * @throws MessagingException 
353 	 */
354 	private void setContentTransferEncoding(MimePart mimePart) throws MessagingException {
355 		String contentTransferEncoding = "7bit";
356 		if ("UTF-8".equalsIgnoreCase(charset)) {
357 			contentTransferEncoding = "8bit";
358 		}
359 		mimePart.setHeader("Content-Transfer-Encoding", contentTransferEncoding);
360 	}
361 
362 	/***
363 	 * @param mail
364 	 * @throws MessagingException
365 	 * @throws UnsupportedEncodingException
366 	 */
367 	private void setSubject(Mail mail) throws UnsupportedEncodingException, MessagingException {
368 		if (charset != null) {
369 			if (Mail.JIS_CHARSET.equalsIgnoreCase(charset)) {
370 				String subject = Cp932.toJIS(mail.getSubject());
371 				mimeMessage.setSubject(MimeUtility.encodeText(subject, charset, "B"));
372 			} else {
373 				mimeMessage.setSubject(mail.getSubject(), charset);
374 			}
375 		} else {
376 			mimeMessage.setSubject(mail.getSubject());
377 		}
378 	}
379 
380 	/***
381 	 * @param mail
382 	 * @throws MessagingException 
383 	 * @throws UnsupportedEncodingException 
384 	 */
385 	private void setFrom(Mail mail) throws MessagingException, UnsupportedEncodingException {
386 		InternetAddress address = convertCharset(mail.getFrom());
387 		mimeMessage.setFrom(address);
388 	}
389 
390 	private InternetAddress convertCharset(InternetAddress address)
391 																	throws UnsupportedEncodingException {
392 		String name = address.getPersonal();
393 		if (name != null && !"".equals(name) && Mail.JIS_CHARSET.equalsIgnoreCase(charset)) {
394 			name = Cp932.toJIS(name);
395 		}
396 		return new InternetAddress(address.getAddress(), name, charset);
397 	}
398 
399 	private InternetAddress[] convertCharset(InternetAddress[] addresses)
400 																			throws UnsupportedEncodingException {
401 		for (int i = 0; i < addresses.length; i++) {
402 			addresses[i] = convertCharset(addresses[i]);
403 		}
404 		return addresses;
405 	}
406 
407 	/***
408 	 * 添付ファイルデータを指定されたMimeBodyPartにセットします。
409 	 * 
410 	 * @since 1.1
411 	 * 
412 	 * @param fileName
413 	 * @param dataSource
414 	 * @param mimeBodyPart ファイルデータをセットするMimeBodyPart
415 	 * @throws UnsupportedEncodingException
416 	 * @throws MessagingException
417 	 */
418 	private void addAttachment(String fileName, DataSource dataSource, MimeBodyPart mimeBodyPart)
419 																									throws UnsupportedEncodingException,
420 																									MessagingException {
421 		if (charset != null) {
422 			// ファイル名のエンコード
423 			mimeBodyPart.setFileName(MimeUtility.encodeText(fileName, charset, "B"));
424 		} else {
425 			mimeBodyPart.setFileName(fileName);
426 		}
427 
428 		mimeBodyPart.setDataHandler(new DataHandler(dataSource));
429 	}
430 
431 }