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