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 }