001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package org.apache.commons.mail; 018 019 import java.io.File; 020 import java.io.IOException; 021 import java.io.InputStream; 022 import java.net.URL; 023 024 import javax.activation.DataHandler; 025 import javax.activation.DataSource; 026 import javax.activation.FileDataSource; 027 import javax.activation.URLDataSource; 028 import javax.mail.BodyPart; 029 import javax.mail.MessagingException; 030 import javax.mail.internet.MimeBodyPart; 031 import javax.mail.internet.MimeMultipart; 032 import javax.mail.internet.MimePart; 033 034 /** 035 * A multipart email. 036 * 037 * <p>This class is used to send multi-part internet email like 038 * messages with attachments. 039 * 040 * <p>To create a multi-part email, call the default constructor and 041 * then you can call setMsg() to set the message and call the 042 * different attach() methods. 043 * 044 * @since 1.0 045 * @author <a href="mailto:quintonm@bellsouth.net">Quinton McCombs</a> 046 * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a> 047 * @author <a href="mailto:frank.kim@clearink.com">Frank Y. Kim</a> 048 * @author <a href="mailto:bmclaugh@algx.net">Brett McLaughlin</a> 049 * @author <a href="mailto:unknown">Regis Koenig</a> 050 * @author <a href="mailto:corey.scott@gmail.com">Corey Scott</a> 051 * @version $Id: MultiPartEmail.java 741633 2009-02-06 17:02:44Z sgoeschl $ 052 */ 053 public class MultiPartEmail extends Email 054 { 055 /** Body portion of the email. */ 056 private MimeMultipart container; 057 058 /** The message container. */ 059 private BodyPart primaryBodyPart; 060 061 /** The MIME subtype. */ 062 private String subType; 063 064 /** Indicates if the message has been initialized */ 065 private boolean initialized; 066 067 /** Indicates if attachments have been added to the message */ 068 private boolean boolHasAttachments; 069 070 /** 071 * Set the MIME subtype of the email. 072 * 073 * @param aSubType MIME subtype of the email 074 * @since 1.0 075 */ 076 public void setSubType(String aSubType) 077 { 078 this.subType = aSubType; 079 } 080 081 /** 082 * Get the MIME subtype of the email. 083 * 084 * @return MIME subtype of the email 085 * @since 1.0 086 */ 087 public String getSubType() 088 { 089 return subType; 090 } 091 092 /** 093 * Add a new part to the email. 094 * 095 * @param partContent The content. 096 * @param partContentType The content type. 097 * @return An Email. 098 * @throws EmailException see javax.mail.internet.MimeBodyPart 099 * for definitions 100 * @since 1.0 101 */ 102 public Email addPart(String partContent, String partContentType) 103 throws EmailException 104 { 105 BodyPart bodyPart = createBodyPart(); 106 try 107 { 108 bodyPart.setContent(partContent, partContentType); 109 getContainer().addBodyPart(bodyPart); 110 } 111 catch (MessagingException me) 112 { 113 throw new EmailException(me); 114 } 115 116 return this; 117 } 118 119 /** 120 * Add a new part to the email. 121 * 122 * @param multipart The MimeMultipart. 123 * @return An Email. 124 * @throws EmailException see javax.mail.internet.MimeBodyPart 125 * for definitions 126 * @since 1.0 127 */ 128 public Email addPart(MimeMultipart multipart) throws EmailException 129 { 130 try 131 { 132 return addPart(multipart, getContainer().getCount()); 133 } 134 catch (MessagingException me) 135 { 136 throw new EmailException(me); 137 } 138 } 139 140 /** 141 * Add a new part to the email. 142 * 143 * @param multipart The part to add. 144 * @param index The index to add at. 145 * @return The email. 146 * @throws EmailException An error occured while adding the part. 147 * @since 1.0 148 */ 149 public Email addPart(MimeMultipart multipart, int index) throws EmailException 150 { 151 BodyPart bodyPart = createBodyPart(); 152 try 153 { 154 bodyPart.setContent(multipart); 155 getContainer().addBodyPart(bodyPart, index); 156 } 157 catch (MessagingException me) 158 { 159 throw new EmailException(me); 160 } 161 162 return this; 163 } 164 165 /** 166 * Initialize the multipart email. 167 * @since 1.0 168 */ 169 protected void init() 170 { 171 if (initialized) 172 { 173 throw new IllegalStateException("Already initialized"); 174 } 175 176 container = createMimeMultipart(); 177 super.setContent(container); 178 179 initialized = true; 180 } 181 182 /** 183 * Set the message of the email. 184 * 185 * @param msg A String. 186 * @return An Email. 187 * @throws EmailException see javax.mail.internet.MimeBodyPart 188 * for definitions 189 * @since 1.0 190 */ 191 public Email setMsg(String msg) throws EmailException 192 { 193 // throw exception on null message 194 if (EmailUtils.isEmpty(msg)) 195 { 196 throw new EmailException("Invalid message supplied"); 197 } 198 try 199 { 200 BodyPart primary = getPrimaryBodyPart(); 201 202 if ((primary instanceof MimePart) && EmailUtils.isNotEmpty(charset)) 203 { 204 ((MimePart) primary).setText(msg, charset); 205 } 206 else 207 { 208 primary.setText(msg); 209 } 210 } 211 catch (MessagingException me) 212 { 213 throw new EmailException(me); 214 } 215 return this; 216 } 217 218 /** 219 * Builds the actual MimeMessage 220 * 221 * @throws EmailException see javax.mail.internet.MimeBodyPart 222 * for definitions 223 * @since 1.0 224 */ 225 public void buildMimeMessage() throws EmailException 226 { 227 try 228 { 229 if (primaryBodyPart != null) 230 { 231 // before a multipart message can be sent, we must make sure that 232 // the content for the main body part was actually set. If not, 233 // an IOException will be thrown during super.send(). 234 235 BodyPart body = this.getPrimaryBodyPart(); 236 try 237 { 238 body.getContent(); 239 } 240 catch (IOException e) 241 { 242 // do nothing here. content will be set to an empty string 243 // as a result. 244 // (Should this really be rethrown as an email exception?) 245 // throw new EmailException(e); 246 } 247 } 248 249 if (subType != null) 250 { 251 getContainer().setSubType(subType); 252 } 253 254 super.buildMimeMessage(); 255 } 256 catch (MessagingException me) 257 { 258 throw new EmailException(me); 259 } 260 } 261 262 /** 263 * Attach an EmailAttachment. 264 * 265 * @param attachment An EmailAttachment. 266 * @return A MultiPartEmail. 267 * @throws EmailException see javax.mail.internet.MimeBodyPart 268 * for definitions 269 * @since 1.0 270 */ 271 public MultiPartEmail attach(EmailAttachment attachment) 272 throws EmailException 273 { 274 MultiPartEmail result = null; 275 276 if (attachment == null) 277 { 278 throw new EmailException("Invalid attachment supplied"); 279 } 280 281 URL url = attachment.getURL(); 282 283 if (url == null) 284 { 285 String fileName = null; 286 try 287 { 288 fileName = attachment.getPath(); 289 File file = new File(fileName); 290 if (!file.exists()) 291 { 292 throw new IOException( 293 "\"" + fileName + "\" does not exist"); 294 } 295 result = 296 attach( 297 new FileDataSource(file), 298 attachment.getName(), 299 attachment.getDescription(), 300 attachment.getDisposition()); 301 } 302 catch (IOException e) 303 { 304 throw new EmailException( 305 "Cannot attach file \"" + fileName + "\"", 306 e); 307 } 308 } 309 else 310 { 311 result = 312 attach( 313 url, 314 attachment.getName(), 315 attachment.getDescription(), 316 attachment.getDisposition()); 317 } 318 319 return result; 320 } 321 322 /** 323 * Attach a file located by its URL. The disposition of the file 324 * is set to mixed. 325 * 326 * @param url The URL of the file (may be any valid URL). 327 * @param name The name field for the attachment. 328 * @param description A description for the attachment. 329 * @return A MultiPartEmail. 330 * @throws EmailException see javax.mail.internet.MimeBodyPart 331 * for definitions 332 * @since 1.0 333 */ 334 public MultiPartEmail attach(URL url, String name, String description) 335 throws EmailException 336 { 337 return attach(url, name, description, EmailAttachment.ATTACHMENT); 338 } 339 340 /** 341 * Attach a file located by its URL. 342 * 343 * @param url The URL of the file (may be any valid URL). 344 * @param name The name field for the attachment. 345 * @param description A description for the attachment. 346 * @param disposition Either mixed or inline. 347 * @return A MultiPartEmail. 348 * @throws EmailException see javax.mail.internet.MimeBodyPart 349 * for definitions 350 * @since 1.0 351 */ 352 public MultiPartEmail attach( 353 URL url, 354 String name, 355 String description, 356 String disposition) 357 throws EmailException 358 { 359 // verify that the URL is valid 360 try 361 { 362 InputStream is = url.openStream(); 363 is.close(); 364 } 365 catch (IOException e) 366 { 367 throw new EmailException("Invalid URL set:" + url, e); 368 } 369 370 return attach(new URLDataSource(url), name, description, disposition); 371 } 372 373 /** 374 * Attach a file specified as a DataSource interface. 375 * 376 * @param ds A DataSource interface for the file. 377 * @param name The name field for the attachment. 378 * @param description A description for the attachment. 379 * @return A MultiPartEmail. 380 * @throws EmailException see javax.mail.internet.MimeBodyPart 381 * for definitions 382 * @since 1.0 383 */ 384 public MultiPartEmail attach( 385 DataSource ds, 386 String name, 387 String description) 388 throws EmailException 389 { 390 // verify that the DataSource is valid 391 try 392 { 393 if (ds == null || ds.getInputStream() == null) 394 { 395 throw new EmailException("Invalid Datasource"); 396 } 397 } 398 catch (IOException e) 399 { 400 throw new EmailException("Invalid Datasource", e); 401 } 402 403 return attach(ds, name, description, EmailAttachment.ATTACHMENT); 404 } 405 406 /** 407 * Attach a file specified as a DataSource interface. 408 * 409 * @param ds A DataSource interface for the file. 410 * @param name The name field for the attachment. 411 * @param description A description for the attachment. 412 * @param disposition Either mixed or inline. 413 * @return A MultiPartEmail. 414 * @throws EmailException see javax.mail.internet.MimeBodyPart 415 * for definitions 416 * @since 1.0 417 */ 418 public MultiPartEmail attach( 419 DataSource ds, 420 String name, 421 String description, 422 String disposition) 423 throws EmailException 424 { 425 if (EmailUtils.isEmpty(name)) 426 { 427 name = ds.getName(); 428 } 429 BodyPart bodyPart = createBodyPart(); 430 try 431 { 432 getContainer().addBodyPart(bodyPart); 433 434 bodyPart.setDisposition(disposition); 435 bodyPart.setFileName(name); 436 bodyPart.setDescription(description); 437 bodyPart.setDataHandler(new DataHandler(ds)); 438 } 439 catch (MessagingException me) 440 { 441 throw new EmailException(me); 442 } 443 setBoolHasAttachments(true); 444 445 return this; 446 } 447 448 /** 449 * Gets first body part of the message. 450 * 451 * @return The primary body part. 452 * @throws MessagingException An error occured while getting the primary body part. 453 * @since 1.0 454 */ 455 protected BodyPart getPrimaryBodyPart() throws MessagingException 456 { 457 if (!initialized) 458 { 459 init(); 460 } 461 462 // Add the first body part to the message. The fist body part must be 463 if (this.primaryBodyPart == null) 464 { 465 primaryBodyPart = createBodyPart(); 466 getContainer().addBodyPart(primaryBodyPart, 0); 467 } 468 469 return primaryBodyPart; 470 } 471 472 /** 473 * Gets the message container. 474 * 475 * @return The message container. 476 * @since 1.0 477 */ 478 protected MimeMultipart getContainer() 479 { 480 if (!initialized) 481 { 482 init(); 483 } 484 return container; 485 } 486 487 /** 488 * Creates a body part object. 489 * Can be overridden if you don't want to create a BodyPart. 490 * 491 * @return the created body part 492 */ 493 protected BodyPart createBodyPart() 494 { 495 BodyPart bodyPart = new MimeBodyPart(); 496 return bodyPart; 497 } 498 /** 499 * Creates a mime multipart object. 500 * 501 * @return the created mime part 502 */ 503 protected MimeMultipart createMimeMultipart() 504 { 505 MimeMultipart mmp = new MimeMultipart(); 506 return mmp; 507 } 508 509 /** 510 * Checks whether there are attachments. 511 * 512 * @return true if there are attachments 513 * @since 1.0 514 */ 515 public boolean isBoolHasAttachments() 516 { 517 return boolHasAttachments; 518 } 519 520 /** 521 * Sets whether there are attachments. 522 * 523 * @param b the attachments flag 524 * @since 1.0 525 */ 526 public void setBoolHasAttachments(boolean b) 527 { 528 boolHasAttachments = b; 529 } 530 531 /** 532 * Checks if this object is initialized. 533 * 534 * @return true if initialized 535 */ 536 protected boolean isInitialized() 537 { 538 return initialized; 539 } 540 541 /** 542 * Sets the initialized status of this object. 543 * 544 * @param b the initialized status flag 545 */ 546 protected void setInitialized(boolean b) 547 { 548 initialized = b; 549 } 550 551 }