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.UnsupportedEncodingException; 020 import java.nio.charset.Charset; 021 import java.util.ArrayList; 022 import java.util.Collection; 023 import java.util.Date; 024 import java.util.HashMap; 025 import java.util.Iterator; 026 import java.util.List; 027 import java.util.Map; 028 import java.util.Properties; 029 030 import javax.mail.Authenticator; 031 import javax.mail.Message; 032 import javax.mail.MessagingException; 033 import javax.mail.Session; 034 import javax.mail.Store; 035 import javax.mail.Transport; 036 import javax.mail.internet.AddressException; 037 import javax.mail.internet.InternetAddress; 038 import javax.mail.internet.MimeMessage; 039 import javax.mail.internet.MimeMultipart; 040 import javax.naming.Context; 041 import javax.naming.InitialContext; 042 import javax.naming.NamingException; 043 044 /** 045 * The base class for all email messages. This class sets the 046 * sender's email & name, receiver's email & name, subject, and the 047 * sent date. Subclasses are responsible for setting the message 048 * body. 049 * 050 * @since 1.0 051 * @author <a href="mailto:quintonm@bellsouth.net">Quinton McCombs</a> 052 * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a> 053 * @author <a href="mailto:frank.kim@clearink.com">Frank Y. Kim</a> 054 * @author <a href="mailto:bmclaugh@algx.net">Brett McLaughlin</a> 055 * @author <a href="mailto:greg@shwoop.com">Greg Ritter</a> 056 * @author <a href="mailto:unknown">Regis Koenig</a> 057 * @author <a href="mailto:colin.chalmers@maxware.nl">Colin Chalmers</a> 058 * @author <a href="mailto:matthias@wessendorf.net">Matthias Wessendorf</a> 059 * @author <a href="mailto:corey.scott@gmail.com">Corey Scott</a> 060 * @version $Revision: 577476 $ $Date: 2007-09-19 16:50:30 -0700 (Wed, 19 Sep 2007) $ 061 * @version $Id: Email.java 577476 2007-09-19 23:50:30Z bspeakmon $ 062 */ 063 public abstract class Email 064 { 065 /** Constants used by Email classes. */ 066 067 /** */ 068 public static final String SENDER_EMAIL = "sender.email"; 069 /** */ 070 public static final String SENDER_NAME = "sender.name"; 071 /** */ 072 public static final String RECEIVER_EMAIL = "receiver.email"; 073 /** */ 074 public static final String RECEIVER_NAME = "receiver.name"; 075 /** */ 076 public static final String EMAIL_SUBJECT = "email.subject"; 077 /** */ 078 public static final String EMAIL_BODY = "email.body"; 079 /** */ 080 public static final String CONTENT_TYPE = "content.type"; 081 082 /** */ 083 public static final String MAIL_HOST = "mail.smtp.host"; 084 /** */ 085 public static final String MAIL_PORT = "mail.smtp.port"; 086 /** */ 087 public static final String MAIL_SMTP_FROM = "mail.smtp.from"; 088 /** */ 089 public static final String MAIL_SMTP_AUTH = "mail.smtp.auth"; 090 /** */ 091 public static final String MAIL_SMTP_USER = "mail.smtp.user"; 092 /** */ 093 public static final String MAIL_SMTP_PASSWORD = "mail.smtp.password"; 094 /** */ 095 public static final String MAIL_TRANSPORT_PROTOCOL = 096 "mail.transport.protocol"; 097 /** 098 * @since 1.1 099 */ 100 public static final String MAIL_TRANSPORT_TLS = "mail.smtp.starttls.enable"; 101 /** */ 102 public static final String MAIL_SMTP_SOCKET_FACTORY_FALLBACK = "mail.smtp.socketFactory.fallback"; 103 /** */ 104 public static final String MAIL_SMTP_SOCKET_FACTORY_CLASS = "mail.smtp.socketFactory.class"; 105 /** */ 106 public static final String MAIL_SMTP_SOCKET_FACTORY_PORT = "mail.smtp.socketFactory.port"; 107 /** */ 108 public static final String SMTP = "smtp"; 109 /** */ 110 public static final String TEXT_HTML = "text/html"; 111 /** */ 112 public static final String TEXT_PLAIN = "text/plain"; 113 /** */ 114 public static final String ATTACHMENTS = "attachments"; 115 /** */ 116 public static final String FILE_SERVER = "file.server"; 117 /** */ 118 public static final String MAIL_DEBUG = "mail.debug"; 119 120 /** */ 121 public static final String KOI8_R = "koi8-r"; 122 /** */ 123 public static final String ISO_8859_1 = "iso-8859-1"; 124 /** */ 125 public static final String US_ASCII = "us-ascii"; 126 127 /** The email message to send. */ 128 protected MimeMessage message; 129 130 /** The charset to use for this message */ 131 protected String charset; 132 133 /** The Address of the sending party, mandatory */ 134 protected InternetAddress fromAddress; 135 136 /** The Subject */ 137 protected String subject; 138 139 /** An attachment */ 140 protected MimeMultipart emailBody; 141 142 /** The content */ 143 protected Object content; 144 145 /** The content type */ 146 protected String contentType; 147 148 /** Set session debugging on or off */ 149 protected boolean debug; 150 151 /** Sent date */ 152 protected Date sentDate; 153 154 /** 155 * Instance of an <code>Authenticator</code> object that will be used 156 * when authentication is requested from the mail server. 157 */ 158 protected Authenticator authenticator; 159 160 /** 161 * The hostname of the mail server with which to connect. If null will try 162 * to get property from system.properties. If still null, quit 163 */ 164 protected String hostName; 165 166 /** 167 * The port number of the mail server to connect to. 168 * Defaults to the standard port ( 25 ). 169 */ 170 protected String smtpPort = "25"; 171 172 /** 173 * The port number of the SSL enabled SMTP server; 174 * defaults to the standard port, 465. 175 */ 176 protected String sslSmtpPort = "465"; 177 178 /** List of "to" email adresses */ 179 protected List toList = new ArrayList(); 180 181 /** List of "cc" email adresses */ 182 protected List ccList = new ArrayList(); 183 184 /** List of "bcc" email adresses */ 185 protected List bccList = new ArrayList(); 186 187 /** List of "replyTo" email adresses */ 188 protected List replyList = new ArrayList(); 189 190 /** 191 * Address to which undeliverable mail should be sent. 192 * Because this is handled by JavaMail as a String property 193 * in the mail session, this property is of type <code>String</code> 194 * rather than <code>InternetAddress</code>. 195 */ 196 protected String bounceAddress; 197 198 /** 199 * Used to specify the mail headers. Example: 200 * 201 * X-Mailer: Sendmail, X-Priority: 1( highest ) 202 * or 2( high ) 3( normal ) 4( low ) and 5( lowest ) 203 * Disposition-Notification-To: user@domain.net 204 */ 205 protected Map headers = new HashMap(); 206 207 /** 208 * Used to determine whether to use pop3 before smtp, and if so the settings. 209 */ 210 protected boolean popBeforeSmtp; 211 /** the host name of the pop3 server */ 212 protected String popHost; 213 /** the user name to log into the pop3 server */ 214 protected String popUsername; 215 /** the password to log into the pop3 server */ 216 protected String popPassword; 217 218 /** does server require TLS encryption for authentication */ 219 protected boolean tls; 220 /** does the current transport use SSL encryption? */ 221 protected boolean ssl; 222 223 /** The Session to mail with */ 224 private Session session; 225 226 /** 227 * Setting to true will enable the display of debug information. 228 * 229 * @param d A boolean. 230 * @since 1.0 231 */ 232 public void setDebug(boolean d) 233 { 234 this.debug = d; 235 } 236 237 /** 238 * Sets the userName and password if authentication is needed. If this 239 * method is not used, no authentication will be performed. 240 * <p> 241 * This method will create a new instance of 242 * <code>DefaultAuthenticator</code> using the supplied parameters. 243 * 244 * @param userName User name for the SMTP server 245 * @param password password for the SMTP server 246 * @see DefaultAuthenticator 247 * @see #setAuthenticator 248 * @since 1.0 249 */ 250 public void setAuthentication(String userName, String password) 251 { 252 this.authenticator = new DefaultAuthenticator(userName, password); 253 this.setAuthenticator(this.authenticator); 254 } 255 256 /** 257 * Sets the <code>Authenticator</code> to be used when authentication 258 * is requested from the mail server. 259 * <p> 260 * This method should be used when your outgoing mail server requires 261 * authentication. Your mail server must also support RFC2554. 262 * 263 * @param newAuthenticator the <code>Authenticator</code> object. 264 * @see Authenticator 265 * @since 1.0 266 */ 267 public void setAuthenticator(Authenticator newAuthenticator) 268 { 269 this.authenticator = newAuthenticator; 270 } 271 272 /** 273 * Set the charset of the message. 274 * 275 * @param newCharset A String. 276 * @throws java.nio.charset.IllegalCharsetNameException if the charset name is invalid 277 * @throws java.nio.charset.UnsupportedCharsetException if no support for the named charset 278 * exists in the current JVM 279 * @since 1.0 280 */ 281 public void setCharset(String newCharset) 282 { 283 Charset set = Charset.forName(newCharset); 284 this.charset = set.name(); 285 } 286 287 /** 288 * Set the emailBody to a MimeMultiPart 289 * 290 * @param aMimeMultipart aMimeMultipart 291 * @since 1.0 292 */ 293 public void setContent(MimeMultipart aMimeMultipart) 294 { 295 this.emailBody = aMimeMultipart; 296 } 297 298 /** 299 * Set the content & contentType 300 * 301 * @param aObject aObject 302 * @param aContentType aContentType 303 * @since 1.0 304 */ 305 public void setContent(Object aObject, String aContentType) 306 { 307 this.content = aObject; 308 if (EmailUtils.isEmpty(aContentType)) 309 { 310 this.contentType = null; 311 } 312 else 313 { 314 // set the content type 315 this.contentType = aContentType; 316 317 // set the charset if the input was properly formed 318 String strMarker = "; charset="; 319 int charsetPos = aContentType.toLowerCase().indexOf(strMarker); 320 321 if (charsetPos != -1) 322 { 323 // find the next space (after the marker) 324 charsetPos += strMarker.length(); 325 int intCharsetEnd = 326 aContentType.toLowerCase().indexOf(" ", charsetPos); 327 328 if (intCharsetEnd != -1) 329 { 330 this.charset = 331 aContentType.substring(charsetPos, intCharsetEnd); 332 } 333 else 334 { 335 this.charset = aContentType.substring(charsetPos); 336 } 337 } 338 else 339 { 340 // use the default charset, if one exists, for messages 341 // whose content-type is some form of text. 342 if (this.contentType.startsWith("text/") && EmailUtils.isNotEmpty(this.charset)) 343 { 344 StringBuffer contentTypeBuf = new StringBuffer(this.contentType); 345 contentTypeBuf.append(strMarker); 346 contentTypeBuf.append(this.charset); 347 this.contentType = contentTypeBuf.toString(); 348 } 349 } 350 } 351 } 352 353 /** 354 * Set the hostname of the outgoing mail server 355 * 356 * @param aHostName aHostName 357 * @since 1.0 358 */ 359 public void setHostName(String aHostName) 360 { 361 this.hostName = aHostName; 362 } 363 364 /** 365 * Set or disable the TLS encryption 366 * 367 * @param withTLS true if TLS needed, false otherwise 368 * @since 1.1 369 */ 370 public void setTLS(boolean withTLS) 371 { 372 this.tls = withTLS; 373 } 374 375 /** 376 * Set the port number of the outgoing mail server. 377 * @param aPortNumber aPortNumber 378 * @since 1.0 379 */ 380 public void setSmtpPort(int aPortNumber) 381 { 382 if (aPortNumber < 1) 383 { 384 throw new IllegalArgumentException( 385 "Cannot connect to a port number that is less than 1 ( " 386 + aPortNumber 387 + " )"); 388 } 389 390 this.smtpPort = Integer.toString(aPortNumber); 391 } 392 393 /** 394 * Supply a mail Session object to use 395 * @param aSession mail session to be used 396 * @since 1.0 397 */ 398 public void setMailSession(Session aSession) 399 { 400 Properties sessionProperties = aSession.getProperties(); 401 String auth = sessionProperties.getProperty(MAIL_SMTP_AUTH); 402 if ("true".equalsIgnoreCase(auth)) 403 { 404 String userName = sessionProperties.getProperty(MAIL_SMTP_USER); 405 String password = sessionProperties.getProperty(MAIL_SMTP_PASSWORD); 406 this.authenticator = new DefaultAuthenticator(userName, password); 407 this.session = Session.getInstance(sessionProperties, this.authenticator); 408 } 409 else 410 { 411 this.session = aSession; 412 } 413 } 414 415 /** 416 * Supply a mail Session object from a JNDI directory 417 * @param jndiName name of JNDI ressource (javax.mail.Session type), ressource 418 * if searched in java:comp/env if name dont start with "java:" 419 * @throws IllegalArgumentException JNDI name null or empty 420 * @throws NamingException ressource can be retrieved from JNDI directory 421 * @since 1.1 422 */ 423 public void setMailSessionFromJNDI(String jndiName) throws NamingException 424 { 425 if (EmailUtils.isEmpty(jndiName)) 426 { 427 throw new IllegalArgumentException("JNDI name missing"); 428 } 429 Context ctx = null; 430 if (jndiName.startsWith("java:")) 431 { 432 ctx = new InitialContext(); 433 } 434 else 435 { 436 ctx = (Context) new InitialContext().lookup("java:comp/env"); 437 438 } 439 this.setMailSession((Session) ctx.lookup(jndiName)); 440 } 441 442 /** 443 * Initialise a mailsession object 444 * 445 * @return A Session. 446 * @throws EmailException thrown when host name was not set. 447 * @since 1.0 448 */ 449 public Session getMailSession() throws EmailException 450 { 451 if (this.session == null) 452 { 453 Properties properties = new Properties(System.getProperties()); 454 properties.setProperty(MAIL_TRANSPORT_PROTOCOL, SMTP); 455 456 if (EmailUtils.isEmpty(this.hostName)) 457 { 458 this.hostName = properties.getProperty(MAIL_HOST); 459 } 460 461 if (EmailUtils.isEmpty(this.hostName)) 462 { 463 throw new EmailException( 464 "Cannot find valid hostname for mail session"); 465 } 466 467 properties.setProperty(MAIL_PORT, smtpPort); 468 properties.setProperty(MAIL_HOST, hostName); 469 properties.setProperty(MAIL_DEBUG, String.valueOf(this.debug)); 470 471 if (this.authenticator != null) 472 { 473 properties.setProperty(MAIL_TRANSPORT_TLS, tls ? "true" : "false"); 474 properties.setProperty(MAIL_SMTP_AUTH, "true"); 475 } 476 477 if (this.ssl) 478 { 479 properties.setProperty(MAIL_PORT, sslSmtpPort); 480 properties.setProperty(MAIL_SMTP_SOCKET_FACTORY_PORT, sslSmtpPort); 481 properties.setProperty(MAIL_SMTP_SOCKET_FACTORY_CLASS, "javax.net.ssl.SSLSocketFactory"); 482 properties.setProperty(MAIL_SMTP_SOCKET_FACTORY_FALLBACK, "false"); 483 } 484 485 if (this.bounceAddress != null) 486 { 487 properties.setProperty(MAIL_SMTP_FROM, this.bounceAddress); 488 } 489 490 // changed this (back) to getInstance due to security exceptions 491 // caused when testing using maven 492 this.session = 493 Session.getInstance(properties, this.authenticator); 494 } 495 return this.session; 496 } 497 498 /** 499 * Creates a InternetAddress. 500 * 501 * @param email An email address. 502 * @param name A name. 503 * @param charsetName The name of the charset to encode the name with. 504 * @return An internet address. 505 * @throws EmailException Thrown when the supplied address, name or charset were invalid. 506 */ 507 private InternetAddress createInternetAddress(String email, String name, String charsetName) 508 throws EmailException 509 { 510 InternetAddress address = null; 511 512 try 513 { 514 address = new InternetAddress(email); 515 516 // check name input 517 if (EmailUtils.isEmpty(name)) 518 { 519 name = email; 520 } 521 522 // check charset input. 523 if (EmailUtils.isEmpty(charsetName)) 524 { 525 address.setPersonal(name); 526 } 527 else 528 { 529 // canonicalize the charset name and make sure 530 // the current platform supports it. 531 Charset set = Charset.forName(charsetName); 532 address.setPersonal(name, set.name()); 533 } 534 535 // run sanity check on new InternetAddress object; if this fails 536 // it will throw AddressException. 537 address.validate(); 538 } 539 catch (AddressException e) 540 { 541 throw new EmailException(e); 542 } 543 catch (UnsupportedEncodingException e) 544 { 545 throw new EmailException(e); 546 } 547 return address; 548 } 549 550 551 /** 552 * Set the FROM field of the email to use the specified address. The email 553 * address will also be used as the personal name. The name will be encoded 554 * using the Java platform's default charset (UTF-16) if it contains 555 * non-ASCII characters; otherwise, it is used as is. 556 * 557 * @param email A String. 558 * @return An Email. 559 * @throws EmailException Indicates an invalid email address. 560 * @since 1.0 561 */ 562 public Email setFrom(String email) 563 throws EmailException 564 { 565 return setFrom(email, null); 566 } 567 568 /** 569 * Set the FROM field of the email to use the specified address and the 570 * specified personal name. The name will be encoded using the Java 571 * platform's default charset (UTF-16) if it contains non-ASCII 572 * characters; otherwise, it is used as is. 573 * 574 * @param email A String. 575 * @param name A String. 576 * @throws EmailException Indicates an invalid email address. 577 * @return An Email. 578 * @since 1.0 579 */ 580 public Email setFrom(String email, String name) 581 throws EmailException 582 { 583 return setFrom(email, name, null); 584 } 585 586 /** 587 * Set the FROM field of the email to use the specified address, personal 588 * name, and charset encoding for the name. 589 * 590 * @param email A String. 591 * @param name A String. 592 * @param charset The charset to encode the name with. 593 * @throws EmailException Indicates an invalid email address or charset. 594 * @return An Email. 595 * @since 1.1 596 */ 597 public Email setFrom(String email, String name, String charset) 598 throws EmailException 599 { 600 this.fromAddress = createInternetAddress(email, name, charset); 601 return this; 602 } 603 604 /** 605 * Add a recipient TO to the email. The email 606 * address will also be used as the personal name. The name will be encoded 607 * using the Java platform's default charset (UTF-16) if it contains 608 * non-ASCII characters; otherwise, it is used as is. 609 * 610 * @param email A String. 611 * @throws EmailException Indicates an invalid email address. 612 * @return An Email. 613 * @since 1.0 614 */ 615 public Email addTo(String email) 616 throws EmailException 617 { 618 return addTo(email, null); 619 } 620 621 /** 622 * Add a recipient TO to the email using the specified address and the 623 * specified personal name. The name will be encoded using the Java 624 * platform's default charset (UTF-16) if it contains non-ASCII 625 * characters; otherwise, it is used as is. 626 * 627 * @param email A String. 628 * @param name A String. 629 * @throws EmailException Indicates an invalid email address. 630 * @return An Email. 631 * @since 1.0 632 */ 633 public Email addTo(String email, String name) 634 throws EmailException 635 { 636 return addTo(email, name, null); 637 } 638 639 /** 640 * Add a recipient TO to the email using the specified address, personal 641 * name, and charset encoding for the name. 642 * 643 * @param email A String. 644 * @param name A String. 645 * @param charset The charset to encode the name with. 646 * @throws EmailException Indicates an invalid email address or charset. 647 * @return An Email. 648 * @since 1.1 649 */ 650 public Email addTo(String email, String name, String charset) 651 throws EmailException 652 { 653 this.toList.add(createInternetAddress(email, name, charset)); 654 return this; 655 } 656 657 /** 658 * Set a list of "TO" addresses. All elements in the specified 659 * <code>Collection</code> are expected to be of type 660 * <code>java.mail.internet.InternetAddress</code>. 661 * 662 * @param aCollection collection of <code>InternetAddress</code> objects. 663 * @throws EmailException Indicates an invalid email address. 664 * @return An Email. 665 * @see javax.mail.internet.InternetAddress 666 * @since 1.0 667 */ 668 public Email setTo(Collection aCollection) throws EmailException 669 { 670 if (aCollection == null || aCollection.isEmpty()) 671 { 672 throw new EmailException("Address List provided was invalid"); 673 } 674 675 this.toList = new ArrayList(aCollection); 676 return this; 677 } 678 679 /** 680 * Add a recipient CC to the email. The email 681 * address will also be used as the personal name. The name will be encoded 682 * using the Java platform's default charset (UTF-16) if it contains 683 * non-ASCII characters; otherwise, it is used as is. 684 * 685 * @param email A String. 686 * @return An Email. 687 * @throws EmailException Indicates an invalid email address. 688 * @since 1.0 689 */ 690 public Email addCc(String email) 691 throws EmailException 692 { 693 return this.addCc(email, null); 694 } 695 696 /** 697 * Add a recipient CC to the email using the specified address and the 698 * specified personal name. The name will be encoded using the Java 699 * platform's default charset (UTF-16) if it contains non-ASCII 700 * characters; otherwise, it is used as is. 701 * 702 * @param email A String. 703 * @param name A String. 704 * @throws EmailException Indicates an invalid email address. 705 * @return An Email. 706 * @since 1.0 707 */ 708 public Email addCc(String email, String name) 709 throws EmailException 710 { 711 return addCc(email, name, null); 712 } 713 714 /** 715 * Add a recipient CC to the email using the specified address, personal 716 * name, and charset encoding for the name. 717 * 718 * @param email A String. 719 * @param name A String. 720 * @param charset The charset to encode the name with. 721 * @throws EmailException Indicates an invalid email address or charset. 722 * @return An Email. 723 * @since 1.1 724 */ 725 public Email addCc(String email, String name, String charset) 726 throws EmailException 727 { 728 this.ccList.add(createInternetAddress(email, name, charset)); 729 return this; 730 } 731 732 /** 733 * Set a list of "CC" addresses. All elements in the specified 734 * <code>Collection</code> are expected to be of type 735 * <code>java.mail.internet.InternetAddress</code>. 736 * 737 * @param aCollection collection of <code>InternetAddress</code> objects. 738 * @return An Email. 739 * @throws EmailException Indicates an invalid email address. 740 * @see javax.mail.internet.InternetAddress 741 * @since 1.0 742 */ 743 public Email setCc(Collection aCollection) throws EmailException 744 { 745 if (aCollection == null || aCollection.isEmpty()) 746 { 747 throw new EmailException("Address List provided was invalid"); 748 } 749 750 this.ccList = new ArrayList(aCollection); 751 return this; 752 } 753 754 /** 755 * Add a blind BCC recipient to the email. The email 756 * address will also be used as the personal name. The name will be encoded 757 * using the Java platform's default charset (UTF-16) if it contains 758 * non-ASCII characters; otherwise, it is used as is. 759 * 760 * @param email A String. 761 * @return An Email. 762 * @throws EmailException Indicates an invalid email address 763 * @since 1.0 764 */ 765 public Email addBcc(String email) 766 throws EmailException 767 { 768 return this.addBcc(email, null); 769 } 770 771 /** 772 * Add a blind BCC recipient to the email using the specified address and 773 * the specified personal name. The name will be encoded using the Java 774 * platform's default charset (UTF-16) if it contains non-ASCII 775 * characters; otherwise, it is used as is. 776 * 777 * @param email A String. 778 * @param name A String. 779 * @return An Email. 780 * @throws EmailException Indicates an invalid email address 781 * @since 1.0 782 */ 783 public Email addBcc(String email, String name) 784 throws EmailException 785 { 786 return addBcc(email, name, null); 787 } 788 789 /** 790 * Add a blind BCC recipient to the email using the specified address, 791 * personal name, and charset encoding for the name. 792 * 793 * @param email A String. 794 * @param name A String. 795 * @param charset The charset to encode the name with. 796 * @return An Email. 797 * @throws EmailException Indicates an invalid email address 798 * @since 1.1 799 */ 800 public Email addBcc(String email, String name, String charset) 801 throws EmailException 802 { 803 this.bccList.add(createInternetAddress(email, name, charset)); 804 return this; 805 } 806 807 /** 808 * Set a list of "BCC" addresses. All elements in the specified 809 * <code>Collection</code> are expected to be of type 810 * <code>java.mail.internet.InternetAddress</code>. 811 * 812 * @param aCollection collection of <code>InternetAddress</code> objects 813 * @return An Email. 814 * @throws EmailException Indicates an invalid email address 815 * @see javax.mail.internet.InternetAddress 816 * @since 1.0 817 */ 818 public Email setBcc(Collection aCollection) throws EmailException 819 { 820 if (aCollection == null || aCollection.isEmpty()) 821 { 822 throw new EmailException("Address List provided was invalid"); 823 } 824 825 this.bccList = new ArrayList(aCollection); 826 return this; 827 } 828 829 /** 830 * Add a reply to address to the email. The email 831 * address will also be used as the personal name. The name will be encoded 832 * using the Java platform's default charset (UTF-16) if it contains 833 * non-ASCII characters; otherwise, it is used as is. 834 * 835 * @param email A String. 836 * @return An Email. 837 * @throws EmailException Indicates an invalid email address 838 * @since 1.0 839 */ 840 public Email addReplyTo(String email) 841 throws EmailException 842 { 843 return this.addReplyTo(email, null); 844 } 845 846 /** 847 * Add a reply to address to the email using the specified address and 848 * the specified personal name. The name will be encoded using the Java 849 * platform's default charset (UTF-16) if it contains non-ASCII 850 * characters; otherwise, it is used as is. 851 * 852 * @param email A String. 853 * @param name A String. 854 * @return An Email. 855 * @throws EmailException Indicates an invalid email address 856 * @since 1.0 857 */ 858 public Email addReplyTo(String email, String name) 859 throws EmailException 860 { 861 return addReplyTo(email, name, null); 862 } 863 864 /** 865 * Add a reply to address to the email using the specified address, 866 * personal name, and charset encoding for the name. 867 * 868 * @param email A String. 869 * @param name A String. 870 * @param charset The charset to encode the name with. 871 * @return An Email. 872 * @throws EmailException Indicates an invalid email address or charset. 873 * @since 1.1 874 */ 875 public Email addReplyTo(String email, String name, String charset) 876 throws EmailException 877 { 878 this.replyList.add(createInternetAddress(email, name, charset)); 879 return this; 880 } 881 882 /** 883 * Set a list of reply to addresses. All elements in the specified 884 * <code>Collection</code> are expected to be of type 885 * <code>java.mail.internet.InternetAddress</code>. 886 * 887 * @param aCollection collection of <code>InternetAddress</code> objects 888 * @return An Email. 889 * @throws EmailException Indicates an invalid email address 890 * @see javax.mail.internet.InternetAddress 891 * @since 1.1 892 */ 893 public Email setReplyTo(Collection aCollection) throws EmailException 894 { 895 if (aCollection == null || aCollection.isEmpty()) 896 { 897 throw new EmailException("Address List provided was invalid"); 898 } 899 900 this.replyList = new ArrayList(aCollection); 901 return this; 902 } 903 904 /** 905 * Used to specify the mail headers. Example: 906 * 907 * X-Mailer: Sendmail, X-Priority: 1( highest ) 908 * or 2( high ) 3( normal ) 4( low ) and 5( lowest ) 909 * Disposition-Notification-To: user@domain.net 910 * 911 * @param map A Map. 912 * @since 1.0 913 */ 914 public void setHeaders(Map map) 915 { 916 Iterator iterKeyBad = map.entrySet().iterator(); 917 918 while (iterKeyBad.hasNext()) 919 { 920 Map.Entry entry = (Map.Entry) iterKeyBad.next(); 921 String strName = (String) entry.getKey(); 922 String strValue = (String) entry.getValue(); 923 924 if (EmailUtils.isEmpty(strName)) 925 { 926 throw new IllegalArgumentException("name can not be null"); 927 } 928 if (EmailUtils.isEmpty(strValue)) 929 { 930 throw new IllegalArgumentException("value can not be null"); 931 } 932 } 933 934 // all is ok, update headers 935 this.headers = map; 936 } 937 938 /** 939 * Adds a header ( name, value ) to the headers Map. 940 * 941 * @param name A String with the name. 942 * @param value A String with the value. 943 * @since 1.0 944 */ 945 public void addHeader(String name, String value) 946 { 947 if (EmailUtils.isEmpty(name)) 948 { 949 throw new IllegalArgumentException("name can not be null"); 950 } 951 if (EmailUtils.isEmpty(value)) 952 { 953 throw new IllegalArgumentException("value can not be null"); 954 } 955 956 this.headers.put(name, value); 957 } 958 959 /** 960 * Set the email subject. 961 * 962 * @param aSubject A String. 963 * @return An Email. 964 * @since 1.0 965 */ 966 public Email setSubject(String aSubject) 967 { 968 this.subject = aSubject; 969 return this; 970 } 971 972 /** 973 * Set the "bounce address" - the address to which undeliverable messages 974 * will be returned. If this value is never set, then the message will be 975 * sent to the address specified with the System property "mail.smtp.from", 976 * or if that value is not set, then to the "from" address. 977 * 978 * @param email A String. 979 * @return An Email. 980 * @since 1.0 981 */ 982 public Email setBounceAddress(String email) 983 { 984 this.bounceAddress = email; 985 return this; 986 } 987 988 989 /** 990 * Define the content of the mail. It should be overidden by the 991 * subclasses. 992 * 993 * @param msg A String. 994 * @return An Email. 995 * @throws EmailException generic exception. 996 * @since 1.0 997 */ 998 public abstract Email setMsg(String msg) throws EmailException; 999 1000 /** 1001 * Build the internal MimeMessage to be sent. 1002 * 1003 * @throws EmailException if there was an error. 1004 * @since 1.0 1005 */ 1006 public void buildMimeMessage() throws EmailException 1007 { 1008 try 1009 { 1010 this.getMailSession(); 1011 this.message = new MimeMessage(this.session); 1012 1013 if (EmailUtils.isNotEmpty(this.subject)) 1014 { 1015 if (EmailUtils.isNotEmpty(this.charset)) 1016 { 1017 this.message.setSubject(this.subject, this.charset); 1018 } 1019 else 1020 { 1021 this.message.setSubject(this.subject); 1022 } 1023 } 1024 1025 // ======================================================== 1026 // Start of replacement code 1027 if (this.content != null) 1028 { 1029 this.message.setContent(this.content, this.contentType); 1030 } 1031 // end of replacement code 1032 // ======================================================== 1033 else if (this.emailBody != null) 1034 { 1035 this.message.setContent(this.emailBody); 1036 } 1037 else 1038 { 1039 this.message.setContent("", Email.TEXT_PLAIN); 1040 } 1041 1042 if (this.fromAddress != null) 1043 { 1044 this.message.setFrom(this.fromAddress); 1045 } 1046 else 1047 { 1048 if (session.getProperty(MAIL_SMTP_FROM) == null) 1049 { 1050 throw new EmailException("From address required"); 1051 } 1052 } 1053 1054 if (this.toList.size() + this.ccList.size() + this.bccList.size() == 0) 1055 { 1056 throw new EmailException( 1057 "At least one receiver address required"); 1058 } 1059 1060 if (this.toList.size() > 0) 1061 { 1062 this.message.setRecipients( 1063 Message.RecipientType.TO, 1064 this.toInternetAddressArray(this.toList)); 1065 } 1066 1067 if (this.ccList.size() > 0) 1068 { 1069 this.message.setRecipients( 1070 Message.RecipientType.CC, 1071 this.toInternetAddressArray(this.ccList)); 1072 } 1073 1074 if (this.bccList.size() > 0) 1075 { 1076 this.message.setRecipients( 1077 Message.RecipientType.BCC, 1078 this.toInternetAddressArray(this.bccList)); 1079 } 1080 1081 if (this.replyList.size() > 0) 1082 { 1083 this.message.setReplyTo( 1084 this.toInternetAddressArray(this.replyList)); 1085 } 1086 1087 if (this.headers.size() > 0) 1088 { 1089 Iterator iterHeaderKeys = this.headers.keySet().iterator(); 1090 while (iterHeaderKeys.hasNext()) 1091 { 1092 String name = (String) iterHeaderKeys.next(); 1093 String value = (String) headers.get(name); 1094 this.message.addHeader(name, value); 1095 } 1096 } 1097 1098 if (this.message.getSentDate() == null) 1099 { 1100 this.message.setSentDate(getSentDate()); 1101 } 1102 1103 if (this.popBeforeSmtp) 1104 { 1105 Store store = session.getStore("pop3"); 1106 store.connect(this.popHost, this.popUsername, this.popPassword); 1107 } 1108 } 1109 catch (MessagingException me) 1110 { 1111 throw new EmailException(me); 1112 } 1113 } 1114 1115 /** 1116 * Sends the previously created MimeMessage to the SMTP server. 1117 * 1118 * @return the message id of the underlying MimeMessage 1119 * @throws EmailException the sending failed 1120 */ 1121 public String sendMimeMessage() 1122 throws EmailException 1123 { 1124 EmailUtils.notNull(this.message, "message"); 1125 1126 try 1127 { 1128 Transport.send(this.message); 1129 return this.message.getMessageID(); 1130 } 1131 catch (Throwable t) 1132 { 1133 String msg = "Sending the email to the following server failed : " 1134 + this.getHostName() 1135 + ":" 1136 + this.getSmtpPort(); 1137 1138 throw new EmailException(msg, t); 1139 } 1140 } 1141 1142 /** 1143 * Returns the internal MimeMessage. Please not that the 1144 * MimeMessage is build by the buildMimeMessage() method. 1145 * 1146 * @return the MimeMessage 1147 */ 1148 public MimeMessage getMimeMessage() 1149 { 1150 return this.message; 1151 } 1152 1153 /** 1154 * Sends the email. Internally we build a MimeMessage 1155 * which is afterwards sent to the SMTP server. 1156 * 1157 * @return the message id of the underlying MimeMessage 1158 * @throws EmailException the sending failed 1159 */ 1160 public String send() throws EmailException 1161 { 1162 this.buildMimeMessage(); 1163 return this.sendMimeMessage(); 1164 } 1165 1166 /** 1167 * Sets the sent date for the email. The sent date will default to the 1168 * current date if not explictly set. 1169 * 1170 * @param date Date to use as the sent date on the email 1171 * @since 1.0 1172 */ 1173 public void setSentDate(Date date) 1174 { 1175 this.sentDate = date; 1176 } 1177 1178 /** 1179 * Gets the sent date for the email. 1180 * 1181 * @return date to be used as the sent date for the email 1182 * @since 1.0 1183 */ 1184 public Date getSentDate() 1185 { 1186 if (this.sentDate == null) 1187 { 1188 return new Date(); 1189 } 1190 return this.sentDate; 1191 } 1192 1193 /** 1194 * Gets the subject of the email. 1195 * 1196 * @return email subject 1197 */ 1198 public String getSubject() 1199 { 1200 return this.subject; 1201 } 1202 1203 /** 1204 * Gets the sender of the email. 1205 * 1206 * @return from address 1207 */ 1208 public InternetAddress getFromAddress() 1209 { 1210 return this.fromAddress; 1211 } 1212 1213 /** 1214 * Gets the host name of the SMTP server, 1215 * 1216 * @return host name 1217 */ 1218 public String getHostName() 1219 { 1220 if (EmailUtils.isNotEmpty(this.hostName)) 1221 { 1222 return this.hostName; 1223 } 1224 else 1225 { 1226 return this.session.getProperty(MAIL_HOST); 1227 } 1228 } 1229 1230 /** 1231 * Gets the listening port of the SMTP server. 1232 * 1233 * @return smtp port 1234 */ 1235 public String getSmtpPort() 1236 { 1237 if (EmailUtils.isNotEmpty(this.smtpPort)) 1238 { 1239 return this.smtpPort; 1240 } 1241 else 1242 { 1243 return this.session.getProperty(MAIL_PORT); 1244 } 1245 } 1246 1247 /** 1248 * Gets encryption mode for authentication 1249 * 1250 * @return true if using TLS for authentication, false otherwise 1251 * @since 1.1 1252 */ 1253 public boolean isTLS() 1254 { 1255 return this.tls; 1256 } 1257 1258 /** 1259 * Utility to copy List of known InternetAddress objects into an 1260 * array. 1261 * 1262 * @param list A List. 1263 * @return An InternetAddress[]. 1264 * @since 1.0 1265 */ 1266 protected InternetAddress[] toInternetAddressArray(List list) 1267 { 1268 InternetAddress[] ia = 1269 (InternetAddress[]) list.toArray(new InternetAddress[list.size()]); 1270 1271 return ia; 1272 } 1273 1274 /** 1275 * Set details regarding "pop3 before smtp" authentication. 1276 * 1277 * @param newPopBeforeSmtp Wether or not to log into pop3 1278 * server before sending mail. 1279 * @param newPopHost The pop3 host to use. 1280 * @param newPopUsername The pop3 username. 1281 * @param newPopPassword The pop3 password. 1282 * @since 1.0 1283 */ 1284 public void setPopBeforeSmtp( 1285 boolean newPopBeforeSmtp, 1286 String newPopHost, 1287 String newPopUsername, 1288 String newPopPassword) 1289 { 1290 this.popBeforeSmtp = newPopBeforeSmtp; 1291 this.popHost = newPopHost; 1292 this.popUsername = newPopUsername; 1293 this.popPassword = newPopPassword; 1294 } 1295 1296 /** 1297 * Returns whether SSL encryption for the transport is currently enabled. 1298 * @return true if SSL enabled for the transport 1299 */ 1300 public boolean isSSL() 1301 { 1302 return ssl; 1303 } 1304 1305 /** 1306 * Sets whether SSL encryption should be enabled for the SMTP transport. 1307 * @param ssl whether to enable the SSL transport 1308 */ 1309 public void setSSL(boolean ssl) 1310 { 1311 this.ssl = ssl; 1312 } 1313 1314 /** 1315 * Returns the current SSL port used by the SMTP transport. 1316 * @return the current SSL port used by the SMTP transport 1317 */ 1318 public String getSslSmtpPort() 1319 { 1320 if (EmailUtils.isNotEmpty(this.sslSmtpPort)) 1321 { 1322 return this.sslSmtpPort; 1323 } 1324 else 1325 { 1326 return this.session.getProperty(MAIL_SMTP_SOCKET_FACTORY_PORT); 1327 } 1328 } 1329 1330 /** 1331 * Sets the SSL port to use for the SMTP transport. Defaults to the standard 1332 * port, 465. 1333 * @param sslSmtpPort the SSL port to use for the SMTP transport 1334 */ 1335 public void setSslSmtpPort(String sslSmtpPort) 1336 { 1337 this.sslSmtpPort = sslSmtpPort; 1338 } 1339 }