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 */ 017package org.apache.commons.mail; 018 019import java.io.UnsupportedEncodingException; 020import java.nio.charset.Charset; 021import java.util.ArrayList; 022import java.util.Collection; 023import java.util.Date; 024import java.util.HashMap; 025import java.util.Iterator; 026import java.util.List; 027import java.util.Map; 028import java.util.Properties; 029 030import javax.mail.Authenticator; 031import javax.mail.Message; 032import javax.mail.MessagingException; 033import javax.mail.Session; 034import javax.mail.Store; 035import javax.mail.Transport; 036import javax.mail.internet.AddressException; 037import javax.mail.internet.InternetAddress; 038import javax.mail.internet.MimeMessage; 039import javax.mail.internet.MimeMultipart; 040import javax.mail.internet.MimeUtility; 041import javax.naming.Context; 042import javax.naming.InitialContext; 043import javax.naming.NamingException; 044 045/** 046 * The base class for all email messages. This class sets the 047 * sender's email & name, receiver's email & name, subject, and the 048 * sent date. Subclasses are responsible for setting the message 049 * body. 050 * 051 * @since 1.0 052 * @author <a href="mailto:quintonm@bellsouth.net">Quinton McCombs</a> 053 * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a> 054 * @author <a href="mailto:frank.kim@clearink.com">Frank Y. Kim</a> 055 * @author <a href="mailto:bmclaugh@algx.net">Brett McLaughlin</a> 056 * @author <a href="mailto:greg@shwoop.com">Greg Ritter</a> 057 * @author <a href="mailto:unknown">Regis Koenig</a> 058 * @author <a href="mailto:colin.chalmers@maxware.nl">Colin Chalmers</a> 059 * @author <a href="mailto:matthias@wessendorf.net">Matthias Wessendorf</a> 060 * @author <a href="mailto:corey.scott@gmail.com">Corey Scott</a> 061 * @version $Id: Email.java 1448626 2013-02-21 12:57:29Z tn $ 062 */ 063public abstract class Email 064{ 065 /** @deprecated since 1.3, use {@link EmailConstants#SENDER_EMAIL} instead */ 066 @Deprecated 067 public static final String SENDER_EMAIL = EmailConstants.SENDER_EMAIL; 068 069 /** @deprecated since 1.3, use {@link EmailConstants#SENDER_NAME} instead */ 070 @Deprecated 071 public static final String SENDER_NAME = EmailConstants.SENDER_NAME; 072 073 /** @deprecated since 1.3, use {@link EmailConstants#RECEIVER_EMAIL} instead */ 074 @Deprecated 075 public static final String RECEIVER_EMAIL = EmailConstants.RECEIVER_EMAIL; 076 077 /** @deprecated since 1.3, use {@link EmailConstants#RECEIVER_NAME} instead */ 078 @Deprecated 079 public static final String RECEIVER_NAME = EmailConstants.RECEIVER_NAME; 080 081 /** @deprecated since 1.3, use {@link EmailConstants#EMAIL_SUBJECT} instead */ 082 @Deprecated 083 public static final String EMAIL_SUBJECT = EmailConstants.EMAIL_SUBJECT; 084 085 /** @deprecated since 1.3, use {@link EmailConstants#EMAIL_BODY} instead */ 086 @Deprecated 087 public static final String EMAIL_BODY = EmailConstants.EMAIL_BODY; 088 089 /** @deprecated since 1.3, use {@link EmailConstants#CONTENT_TYPE} instead */ 090 @Deprecated 091 public static final String CONTENT_TYPE = EmailConstants.CONTENT_TYPE; 092 093 /** @deprecated since 1.3, use {@link EmailConstants#ATTACHMENTS} instead */ 094 @Deprecated 095 public static final String ATTACHMENTS = EmailConstants.ATTACHMENTS; 096 097 /** @deprecated since 1.3, use {@link EmailConstants#FILE_SERVER} instead */ 098 @Deprecated 099 public static final String FILE_SERVER = EmailConstants.FILE_SERVER; 100 101 /** @deprecated since 1.3, use {@link EmailConstants#KOI8_R} instead */ 102 @Deprecated 103 public static final String KOI8_R = EmailConstants.KOI8_R; 104 105 /** @deprecated since 1.3, use {@link EmailConstants#ISO_8859_1} instead */ 106 @Deprecated 107 public static final String ISO_8859_1 = EmailConstants.ISO_8859_1; 108 109 /** @deprecated since 1.3, use {@link EmailConstants#US_ASCII} instead */ 110 @Deprecated 111 public static final String US_ASCII = EmailConstants.US_ASCII; 112 113 /** @deprecated since 1.3, use {@link EmailConstants#MAIL_DEBUG} instead */ 114 @Deprecated 115 public static final String MAIL_DEBUG = EmailConstants.MAIL_DEBUG; 116 117 /** @deprecated since 1.3, use {@link EmailConstants#MAIL_HOST} instead */ 118 @Deprecated 119 public static final String MAIL_HOST = EmailConstants.MAIL_HOST; 120 121 /** @deprecated since 1.3, use {@link EmailConstants#MAIL_PORT} instead */ 122 @Deprecated 123 public static final String MAIL_PORT = EmailConstants.MAIL_PORT; 124 125 /** @deprecated since 1.3, use {@link EmailConstants#MAIL_SMTP_FROM} instead */ 126 @Deprecated 127 public static final String MAIL_SMTP_FROM = EmailConstants.MAIL_SMTP_FROM; 128 129 /** @deprecated since 1.3, use {@link EmailConstants#MAIL_SMTP_AUTH} instead */ 130 @Deprecated 131 public static final String MAIL_SMTP_AUTH = EmailConstants.MAIL_SMTP_AUTH; 132 133 /** @deprecated since 1.3, use {@link EmailConstants#MAIL_SMTP_USER} instead */ 134 @Deprecated 135 public static final String MAIL_SMTP_USER = EmailConstants.MAIL_SMTP_USER; 136 137 /** @deprecated since 1.3, use {@link EmailConstants#MAIL_SMTP_PASSWORD} instead */ 138 @Deprecated 139 public static final String MAIL_SMTP_PASSWORD = EmailConstants.MAIL_SMTP_PASSWORD; 140 141 /** @deprecated since 1.3, use {@link EmailConstants#MAIL_TRANSPORT_PROTOCOL} instead */ 142 @Deprecated 143 public static final String MAIL_TRANSPORT_PROTOCOL = EmailConstants.MAIL_TRANSPORT_PROTOCOL; 144 145 /** @deprecated since 1.3, use {@link EmailConstants#SMTP} instead */ 146 @Deprecated 147 public static final String SMTP = EmailConstants.SMTP; 148 149 /** @deprecated since 1.3, use {@link EmailConstants#TEXT_HTML} instead */ 150 @Deprecated 151 public static final String TEXT_HTML = EmailConstants.TEXT_HTML; 152 153 /** @deprecated since 1.3, use {@link EmailConstants#TEXT_PLAIN} instead */ 154 @Deprecated 155 public static final String TEXT_PLAIN = EmailConstants.TEXT_PLAIN; 156 157 /** @deprecated since 1.3, use {@link EmailConstants#MAIL_TRANSPORT_TLS} instead */ 158 @Deprecated 159 public static final String MAIL_TRANSPORT_TLS = EmailConstants.MAIL_TRANSPORT_TLS; 160 161 /** @deprecated since 1.3, use {@link EmailConstants#MAIL_SMTP_SOCKET_FACTORY_FALLBACK} instead */ 162 @Deprecated 163 public static final String MAIL_SMTP_SOCKET_FACTORY_FALLBACK = EmailConstants.MAIL_SMTP_SOCKET_FACTORY_FALLBACK; 164 165 /** @deprecated since 1.3, use {@link EmailConstants#MAIL_SMTP_SOCKET_FACTORY_CLASS} instead */ 166 @Deprecated 167 public static final String MAIL_SMTP_SOCKET_FACTORY_CLASS = EmailConstants.MAIL_SMTP_SOCKET_FACTORY_CLASS; 168 169 /** @deprecated since 1.3, use {@link EmailConstants#MAIL_SMTP_SOCKET_FACTORY_PORT} instead */ 170 @Deprecated 171 public static final String MAIL_SMTP_SOCKET_FACTORY_PORT = EmailConstants.MAIL_SMTP_SOCKET_FACTORY_PORT; 172 173 /** @deprecated since 1.3, use {@link EmailConstants#MAIL_SMTP_CONNECTIONTIMEOUT} instead */ 174 @Deprecated 175 public static final String MAIL_SMTP_CONNECTIONTIMEOUT = EmailConstants.MAIL_SMTP_CONNECTIONTIMEOUT; 176 177 /** @deprecated since 1.3, use {@link EmailConstants#MAIL_SMTP_TIMEOUT} instead */ 178 @Deprecated 179 public static final String MAIL_SMTP_TIMEOUT = EmailConstants.MAIL_SMTP_TIMEOUT; 180 181 /** The email message to send. */ 182 protected MimeMessage message; 183 184 /** The charset to use for this message. */ 185 protected String charset; 186 187 /** The Address of the sending party, mandatory. */ 188 protected InternetAddress fromAddress; 189 190 /** The Subject. */ 191 protected String subject; 192 193 /** An attachment. */ 194 protected MimeMultipart emailBody; 195 196 /** The content. */ 197 protected Object content; 198 199 /** The content type. */ 200 protected String contentType; 201 202 /** Set session debugging on or off. */ 203 protected boolean debug; 204 205 /** Sent date. */ 206 protected Date sentDate; 207 208 /** 209 * Instance of an <code>Authenticator</code> object that will be used 210 * when authentication is requested from the mail server. 211 */ 212 protected Authenticator authenticator; 213 214 /** 215 * The hostname of the mail server with which to connect. If null will try 216 * to get property from system.properties. If still null, quit. 217 */ 218 protected String hostName; 219 220 /** 221 * The port number of the mail server to connect to. 222 * Defaults to the standard port ( 25 ). 223 */ 224 protected String smtpPort = "25"; 225 226 /** 227 * The port number of the SSL enabled SMTP server; 228 * defaults to the standard port, 465. 229 */ 230 protected String sslSmtpPort = "465"; 231 232 /** List of "to" email addresses. */ 233 protected List<InternetAddress> toList = new ArrayList<InternetAddress>(); 234 235 /** List of "cc" email addresses. */ 236 protected List<InternetAddress> ccList = new ArrayList<InternetAddress>(); 237 238 /** List of "bcc" email addresses. */ 239 protected List<InternetAddress> bccList = new ArrayList<InternetAddress>(); 240 241 /** List of "replyTo" email addresses. */ 242 protected List<InternetAddress> replyList = new ArrayList<InternetAddress>(); 243 244 /** 245 * Address to which undeliverable mail should be sent. 246 * Because this is handled by JavaMail as a String property 247 * in the mail session, this property is of type <code>String</code> 248 * rather than <code>InternetAddress</code>. 249 */ 250 protected String bounceAddress; 251 252 /** 253 * Used to specify the mail headers. Example: 254 * 255 * X-Mailer: Sendmail, X-Priority: 1( highest ) 256 * or 2( high ) 3( normal ) 4( low ) and 5( lowest ) 257 * Disposition-Notification-To: user@domain.net 258 */ 259 protected Map<String, String> headers = new HashMap<String, String>(); 260 261 /** 262 * Used to determine whether to use pop3 before smtp, and if so the settings. 263 */ 264 protected boolean popBeforeSmtp; 265 266 /** the host name of the pop3 server. */ 267 protected String popHost; 268 269 /** the user name to log into the pop3 server. */ 270 protected String popUsername; 271 272 /** the password to log into the pop3 server. */ 273 protected String popPassword; 274 275 /** 276 * Does server require TLS encryption for authentication? 277 * @deprecated since 1.3, use setStartTLSEnabled() instead 278 */ 279 @Deprecated 280 protected boolean tls; 281 282 /** 283 * Does the current transport use SSL/TLS encryption upon connection? 284 * @deprecated since 1.3, use setSSLOnConnect() instead 285 */ 286 @Deprecated 287 protected boolean ssl; 288 289 /** socket I/O timeout value in milliseconds. */ 290 protected int socketTimeout = EmailConstants.SOCKET_TIMEOUT_MS; 291 292 /** socket connection timeout value in milliseconds. */ 293 protected int socketConnectionTimeout = EmailConstants.SOCKET_TIMEOUT_MS; 294 295 /** 296 * If true, enables the use of the STARTTLS command (if supported by 297 * the server) to switch the connection to a TLS-protected connection 298 * before issuing any login commands. Note that an appropriate trust 299 * store must configured so that the client will trust the server's 300 * certificate. 301 * Defaults to false. 302 */ 303 private boolean startTlsEnabled; 304 305 /** 306 * If true, requires the use of the STARTTLS command. If the server doesn't 307 * support the STARTTLS command, or the command fails, the connect method 308 * will fail. 309 * Defaults to false. 310 */ 311 private boolean startTlsRequired; 312 313 /** does the current transport use SSL/TLS encryption upon connection? */ 314 private boolean sslOnConnect; 315 316 /** 317 * If set to true, check the server identity as specified by RFC 2595. These 318 * additional checks based on the content of the server's certificate are 319 * intended to prevent man-in-the-middle attacks. 320 * Defaults to false. 321 */ 322 private boolean sslCheckServerIdentity; 323 324 /** The Session to mail with. */ 325 private Session session; 326 327 /** 328 * Setting to true will enable the display of debug information. 329 * 330 * @param d A boolean. 331 * @since 1.0 332 */ 333 public void setDebug(boolean d) 334 { 335 this.debug = d; 336 } 337 338 /** 339 * Sets the userName and password if authentication is needed. If this 340 * method is not used, no authentication will be performed. 341 * <p> 342 * This method will create a new instance of 343 * <code>DefaultAuthenticator</code> using the supplied parameters. 344 * 345 * @param userName User name for the SMTP server 346 * @param password password for the SMTP server 347 * @see DefaultAuthenticator 348 * @see #setAuthenticator 349 * @since 1.0 350 */ 351 public void setAuthentication(String userName, String password) 352 { 353 this.setAuthenticator(new DefaultAuthenticator(userName, password)); 354 } 355 356 /** 357 * Sets the <code>Authenticator</code> to be used when authentication 358 * is requested from the mail server. 359 * <p> 360 * This method should be used when your outgoing mail server requires 361 * authentication. Your mail server must also support RFC2554. 362 * 363 * @param newAuthenticator the <code>Authenticator</code> object. 364 * @see Authenticator 365 * @since 1.0 366 */ 367 public void setAuthenticator(Authenticator newAuthenticator) 368 { 369 this.authenticator = newAuthenticator; 370 } 371 372 /** 373 * Set the charset of the message. Please note that you should set the charset before 374 * adding the message content. 375 * 376 * @param newCharset A String. 377 * @throws java.nio.charset.IllegalCharsetNameException if the charset name is invalid 378 * @throws java.nio.charset.UnsupportedCharsetException if no support for the named charset 379 * exists in the current JVM 380 * @since 1.0 381 */ 382 public void setCharset(String newCharset) 383 { 384 Charset set = Charset.forName(newCharset); 385 this.charset = set.name(); 386 } 387 388 /** 389 * Set the emailBody to a MimeMultiPart 390 * 391 * @param aMimeMultipart aMimeMultipart 392 * @since 1.0 393 */ 394 public void setContent(MimeMultipart aMimeMultipart) 395 { 396 this.emailBody = aMimeMultipart; 397 } 398 399 /** 400 * Set the content & contentType 401 * 402 * @param aObject aObject 403 * @param aContentType aContentType 404 * @since 1.0 405 */ 406 public void setContent(Object aObject, String aContentType) 407 { 408 this.content = aObject; 409 this.updateContentType(aContentType); 410 } 411 412 /** 413 * Update the contentType. 414 * 415 * @param aContentType aContentType 416 * @since 1.2 417 */ 418 public void updateContentType(final String aContentType) 419 { 420 if (EmailUtils.isEmpty(aContentType)) 421 { 422 this.contentType = null; 423 } 424 else 425 { 426 // set the content type 427 this.contentType = aContentType; 428 429 // set the charset if the input was properly formed 430 String strMarker = "; charset="; 431 int charsetPos = aContentType.toLowerCase().indexOf(strMarker); 432 433 if (charsetPos != -1) 434 { 435 // find the next space (after the marker) 436 charsetPos += strMarker.length(); 437 int intCharsetEnd = 438 aContentType.toLowerCase().indexOf(" ", charsetPos); 439 440 if (intCharsetEnd != -1) 441 { 442 this.charset = 443 aContentType.substring(charsetPos, intCharsetEnd); 444 } 445 else 446 { 447 this.charset = aContentType.substring(charsetPos); 448 } 449 } 450 else 451 { 452 // use the default charset, if one exists, for messages 453 // whose content-type is some form of text. 454 if (this.contentType.startsWith("text/") && EmailUtils.isNotEmpty(this.charset)) 455 { 456 StringBuffer contentTypeBuf = new StringBuffer(this.contentType); 457 contentTypeBuf.append(strMarker); 458 contentTypeBuf.append(this.charset); 459 this.contentType = contentTypeBuf.toString(); 460 } 461 } 462 } 463 } 464 465 /** 466 * Set the hostname of the outgoing mail server. 467 * 468 * @param aHostName aHostName 469 * @since 1.0 470 */ 471 public void setHostName(String aHostName) 472 { 473 checkSessionAlreadyInitialized(); 474 this.hostName = aHostName; 475 } 476 477 /** 478 * Set or disable the STARTTLS encryption. Please see EMAIL-105 479 * for the reasons of deprecation. 480 * 481 * @deprecated since 1.3, use setStartTLSEnabled() instead 482 * @param withTLS true if STARTTLS requested, false otherwise 483 * @since 1.1 484 */ 485 @Deprecated 486 public void setTLS(boolean withTLS) 487 { 488 setStartTLSEnabled(withTLS); 489 } 490 491 /** 492 * Set or disable the STARTTLS encryption. 493 * 494 * @param startTlsEnabled true if STARTTLS requested, false otherwise 495 * @return An Email. 496 * @since 1.3 497 */ 498 public Email setStartTLSEnabled(boolean startTlsEnabled) 499 { 500 checkSessionAlreadyInitialized(); 501 this.startTlsEnabled = startTlsEnabled; 502 this.tls = startTlsEnabled; 503 return this; 504 } 505 506 /** 507 * Set or disable the required STARTTLS encryption. 508 * 509 * @param startTlsRequired true if STARTTLS requested, false otherwise 510 * @return An Email. 511 * @since 1.3 512 */ 513 public Email setStartTLSRequired(boolean startTlsRequired) 514 { 515 checkSessionAlreadyInitialized(); 516 this.startTlsRequired = startTlsRequired; 517 return this; 518 } 519 520 /** 521 * Set the port number of the outgoing mail server. 522 * 523 * @param aPortNumber aPortNumber 524 * @throws IllegalArgumentException if the port number is < 1 525 * @since 1.0 526 */ 527 public void setSmtpPort(int aPortNumber) 528 { 529 checkSessionAlreadyInitialized(); 530 531 if (aPortNumber < 1) 532 { 533 throw new IllegalArgumentException( 534 "Cannot connect to a port number that is less than 1 ( " 535 + aPortNumber 536 + " )"); 537 } 538 539 this.smtpPort = Integer.toString(aPortNumber); 540 } 541 542 /** 543 * Supply a mail Session object to use. Please note that passing 544 * a user name and password (in the case of mail authentication) will 545 * create a new mail session with a DefaultAuthenticator. This is a 546 * convenience but might come unexpected. 547 * 548 * If mail authentication is used but NO username and password 549 * is supplied the implementation assumes that you have set a 550 * authenticator and will use the existing mail session (as expected). 551 * 552 * @param aSession mail session to be used 553 * @throws IllegalArgumentException if the session is {@code null} 554 * @since 1.0 555 */ 556 public void setMailSession(Session aSession) 557 { 558 EmailUtils.notNull(aSession, "no mail session supplied"); 559 560 Properties sessionProperties = aSession.getProperties(); 561 String auth = sessionProperties.getProperty(MAIL_SMTP_AUTH); 562 563 if ("true".equalsIgnoreCase(auth)) 564 { 565 String userName = sessionProperties.getProperty(MAIL_SMTP_USER); 566 String password = sessionProperties.getProperty(MAIL_SMTP_PASSWORD); 567 568 if (EmailUtils.isNotEmpty(userName) && EmailUtils.isNotEmpty(password)) 569 { 570 // only create a new mail session with an authenticator if 571 // authentication is required and no user name is given 572 this.authenticator = new DefaultAuthenticator(userName, password); 573 this.session = Session.getInstance(sessionProperties, this.authenticator); 574 } 575 else 576 { 577 // assume that the given mail session contains a working authenticator 578 this.session = aSession; 579 } 580 } 581 else 582 { 583 this.session = aSession; 584 } 585 } 586 587 /** 588 * Supply a mail Session object from a JNDI directory. 589 * 590 * @param jndiName name of JNDI resource (javax.mail.Session type), resource 591 * if searched in java:comp/env if name does not start with "java:" 592 * @throws IllegalArgumentException if the JNDI name is null or empty 593 * @throws NamingException if the resource cannot be retrieved from JNDI directory 594 * @since 1.1 595 */ 596 public void setMailSessionFromJNDI(String jndiName) throws NamingException 597 { 598 if (EmailUtils.isEmpty(jndiName)) 599 { 600 throw new IllegalArgumentException("JNDI name missing"); 601 } 602 Context ctx = null; 603 if (jndiName.startsWith("java:")) 604 { 605 ctx = new InitialContext(); 606 } 607 else 608 { 609 ctx = (Context) new InitialContext().lookup("java:comp/env"); 610 611 } 612 this.setMailSession((Session) ctx.lookup(jndiName)); 613 } 614 615 /** 616 * Determines the mail session used when sending this Email, creating 617 * the Session if necessary. When a mail session is already 618 * initialized setting the session related properties will cause 619 * an IllegalStateException. 620 * 621 * @return A Session. 622 * @throws EmailException if the host name was not set 623 * @since 1.0 624 */ 625 public Session getMailSession() throws EmailException 626 { 627 if (this.session == null) 628 { 629 Properties properties = new Properties(System.getProperties()); 630 properties.setProperty(MAIL_TRANSPORT_PROTOCOL, SMTP); 631 632 if (EmailUtils.isEmpty(this.hostName)) 633 { 634 this.hostName = properties.getProperty(MAIL_HOST); 635 } 636 637 if (EmailUtils.isEmpty(this.hostName)) 638 { 639 throw new EmailException("Cannot find valid hostname for mail session"); 640 } 641 642 properties.setProperty(MAIL_PORT, this.smtpPort); 643 properties.setProperty(MAIL_HOST, this.hostName); 644 properties.setProperty(MAIL_DEBUG, String.valueOf(this.debug)); 645 646 properties.setProperty(EmailConstants.MAIL_TRANSPORT_STARTTLS_ENABLE, 647 isStartTLSEnabled() ? "true" : "false"); 648 properties.setProperty(EmailConstants.MAIL_TRANSPORT_STARTTLS_REQUIRED, 649 isStartTLSRequired() ? "true" : "false"); 650 651 if (this.authenticator != null) 652 { 653 properties.setProperty(MAIL_SMTP_AUTH, "true"); 654 } 655 656 if (isSSLOnConnect()) 657 { 658 properties.setProperty(MAIL_PORT, this.sslSmtpPort); 659 properties.setProperty(MAIL_SMTP_SOCKET_FACTORY_PORT, this.sslSmtpPort); 660 properties.setProperty(MAIL_SMTP_SOCKET_FACTORY_CLASS, "javax.net.ssl.SSLSocketFactory"); 661 properties.setProperty(MAIL_SMTP_SOCKET_FACTORY_FALLBACK, "false"); 662 } 663 664 if ((isSSLOnConnect() || isStartTLSEnabled()) && isSSLCheckServerIdentity()) 665 { 666 properties.setProperty(EmailConstants.MAIL_SMTP_SSL_CHECKSERVERIDENTITY, "true"); 667 } 668 669 if (this.bounceAddress != null) 670 { 671 properties.setProperty(MAIL_SMTP_FROM, this.bounceAddress); 672 } 673 674 if (this.socketTimeout > 0) 675 { 676 properties.setProperty(MAIL_SMTP_TIMEOUT, Integer.toString(this.socketTimeout)); 677 } 678 679 if (this.socketConnectionTimeout > 0) 680 { 681 properties.setProperty(MAIL_SMTP_CONNECTIONTIMEOUT, Integer.toString(this.socketConnectionTimeout)); 682 } 683 684 // changed this (back) to getInstance due to security exceptions 685 // caused when testing using maven 686 this.session = Session.getInstance(properties, this.authenticator); 687 } 688 return this.session; 689 } 690 691 /** 692 * Set the FROM field of the email to use the specified address. The email 693 * address will also be used as the personal name. 694 * The name will be encoded by the charset of {@link #setCharset(java.lang.String) setCharset()}. 695 * If it is not set, it will be encoded using 696 * the Java platform's default charset (UTF-16) if it contains 697 * non-ASCII characters; otherwise, it is used as is. 698 * 699 * @param email A String. 700 * @return An Email. 701 * @throws EmailException Indicates an invalid email address. 702 * @since 1.0 703 */ 704 public Email setFrom(String email) 705 throws EmailException 706 { 707 return setFrom(email, null); 708 } 709 710 /** 711 * Set the FROM field of the email to use the specified address and the 712 * specified personal name. 713 * The name will be encoded by the charset of {@link #setCharset(java.lang.String) setCharset()}. 714 * If it is not set, it will be encoded using 715 * the Java platform's default charset (UTF-16) if it contains 716 * non-ASCII characters; otherwise, it is used as is. 717 * 718 * @param email A String. 719 * @param name A String. 720 * @return An Email. 721 * @throws EmailException Indicates an invalid email address. 722 * @since 1.0 723 */ 724 public Email setFrom(String email, String name) 725 throws EmailException 726 { 727 return setFrom(email, name, this.charset); 728 } 729 730 /** 731 * Set the FROM field of the email to use the specified address, personal 732 * name, and charset encoding for the name. 733 * 734 * @param email A String. 735 * @param name A String. 736 * @param charset The charset to encode the name with. 737 * @return An Email. 738 * @throws EmailException Indicates an invalid email address or charset. 739 * @since 1.1 740 */ 741 public Email setFrom(String email, String name, String charset) 742 throws EmailException 743 { 744 this.fromAddress = createInternetAddress(email, name, charset); 745 return this; 746 } 747 748 /** 749 * Add a recipient TO to the email. The email 750 * address will also be used as the personal name. 751 * The name will be encoded by the charset of 752 * {@link #setCharset(java.lang.String) setCharset()}. 753 * If it is not set, it will be encoded using 754 * the Java platform's default charset (UTF-16) if it contains 755 * non-ASCII characters; otherwise, it is used as is. 756 * 757 * @param email A String. 758 * @return An Email. 759 * @throws EmailException Indicates an invalid email address. 760 * @since 1.0 761 */ 762 public Email addTo(String email) 763 throws EmailException 764 { 765 return addTo(email, null); 766 } 767 768 /** 769 * Add a list of TO recipients to the email. The email 770 * addresses will also be used as the personal names. 771 * The names will be encoded by the charset of 772 * {@link #setCharset(java.lang.String) setCharset()}. 773 * If it is not set, it will be encoded using 774 * the Java platform's default charset (UTF-16) if it contains 775 * non-ASCII characters; otherwise, it is used as is. 776 * 777 * @param emails A String array. 778 * @return An Email. 779 * @throws EmailException Indicates an invalid email address. 780 * @since 1.3 781 */ 782 public Email addTo(String... emails) 783 throws EmailException 784 { 785 if (emails == null || emails.length == 0) 786 { 787 throw new EmailException("Address List provided was invalid"); 788 } 789 790 for (String email : emails) 791 { 792 addTo(email, null); 793 } 794 795 return this; 796 } 797 798 /** 799 * Add a recipient TO to the email using the specified address and the 800 * specified personal name. 801 * The name will be encoded by the charset of 802 * {@link #setCharset(java.lang.String) setCharset()}. 803 * If it is not set, it will be encoded using 804 * the Java platform's default charset (UTF-16) if it contains 805 * non-ASCII characters; otherwise, it is used as is. 806 * 807 * @param email A String. 808 * @param name A String. 809 * @return An Email. 810 * @throws EmailException Indicates an invalid email address. 811 * @since 1.0 812 */ 813 public Email addTo(String email, String name) 814 throws EmailException 815 { 816 return addTo(email, name, this.charset); 817 } 818 819 /** 820 * Add a recipient TO to the email using the specified address, personal 821 * name, and charset encoding for the name. 822 * 823 * @param email A String. 824 * @param name A String. 825 * @param charset The charset to encode the name with. 826 * @return An Email. 827 * @throws EmailException Indicates an invalid email address or charset. 828 * @since 1.1 829 */ 830 public Email addTo(String email, String name, String charset) 831 throws EmailException 832 { 833 this.toList.add(createInternetAddress(email, name, charset)); 834 return this; 835 } 836 837 /** 838 * Set a list of "TO" addresses. All elements in the specified 839 * <code>Collection</code> are expected to be of type 840 * <code>java.mail.internet.InternetAddress</code>. 841 * 842 * @param aCollection collection of <code>InternetAddress</code> objects. 843 * @return An Email. 844 * @throws EmailException Indicates an invalid email address. 845 * @see javax.mail.internet.InternetAddress 846 * @since 1.0 847 */ 848 public Email setTo(Collection<InternetAddress> aCollection) throws EmailException 849 { 850 if (aCollection == null || aCollection.isEmpty()) 851 { 852 throw new EmailException("Address List provided was invalid"); 853 } 854 855 this.toList = new ArrayList<InternetAddress>(aCollection); 856 return this; 857 } 858 859 /** 860 * Add a recipient CC to the email. The email 861 * address will also be used as the personal name. 862 * The name will be encoded by the charset of {@link #setCharset(java.lang.String) setCharset()}. 863 * If it is not set, it will be encoded using 864 * the Java platform's default charset (UTF-16) if it contains 865 * non-ASCII characters; otherwise, it is used as is. 866 * 867 * @param email A String. 868 * @return An Email. 869 * @throws EmailException Indicates an invalid email address. 870 * @since 1.0 871 */ 872 public Email addCc(String email) 873 throws EmailException 874 { 875 return this.addCc(email, null); 876 } 877 878 /** 879 * Add an array of CC recipients to the email. The email 880 * addresses will also be used as the personal name. 881 * The names will be encoded by the charset of 882 * {@link #setCharset(java.lang.String) setCharset()}. 883 * If it is not set, it will be encoded using 884 * the Java platform's default charset (UTF-16) if it contains 885 * non-ASCII characters; otherwise, it is used as is. 886 * 887 * @param emails A String array. 888 * @return An Email. 889 * @throws EmailException Indicates an invalid email address. 890 * @since 1.3 891 */ 892 public Email addCc(String... emails) 893 throws EmailException 894 { 895 if (emails == null || emails.length == 0) 896 { 897 throw new EmailException("Address List provided was invalid"); 898 } 899 900 for (String email : emails) 901 { 902 addCc(email, null); 903 } 904 905 return this; 906 } 907 908 /** 909 * Add a recipient CC to the email using the specified address and the 910 * specified personal name. 911 * The name will be encoded by the charset of {@link #setCharset(java.lang.String) setCharset()}. 912 * If it is not set, it will be encoded using 913 * the Java platform's default charset (UTF-16) if it contains 914 * non-ASCII characters; otherwise, it is used as is. 915 * 916 * @param email A String. 917 * @param name A String. 918 * @return An Email. 919 * @throws EmailException Indicates an invalid email address. 920 * @since 1.0 921 */ 922 public Email addCc(String email, String name) 923 throws EmailException 924 { 925 return addCc(email, name, this.charset); 926 } 927 928 /** 929 * Add a recipient CC to the email using the specified address, personal 930 * name, and charset encoding for the name. 931 * 932 * @param email A String. 933 * @param name A String. 934 * @param charset The charset to encode the name with. 935 * @return An Email. 936 * @throws EmailException Indicates an invalid email address or charset. 937 * @since 1.1 938 */ 939 public Email addCc(String email, String name, String charset) 940 throws EmailException 941 { 942 this.ccList.add(createInternetAddress(email, name, charset)); 943 return this; 944 } 945 946 /** 947 * Set a list of "CC" addresses. All elements in the specified 948 * <code>Collection</code> are expected to be of type 949 * <code>java.mail.internet.InternetAddress</code>. 950 * 951 * @param aCollection collection of <code>InternetAddress</code> objects. 952 * @return An Email. 953 * @throws EmailException Indicates an invalid email address. 954 * @see javax.mail.internet.InternetAddress 955 * @since 1.0 956 */ 957 public Email setCc(Collection<InternetAddress> aCollection) throws EmailException 958 { 959 if (aCollection == null || aCollection.isEmpty()) 960 { 961 throw new EmailException("Address List provided was invalid"); 962 } 963 964 this.ccList = new ArrayList<InternetAddress>(aCollection); 965 return this; 966 } 967 968 /** 969 * Add a blind BCC recipient to the email. The email 970 * address will also be used as the personal name. 971 * The name will be encoded by the charset of {@link #setCharset(java.lang.String) setCharset()}. 972 * If it is not set, it will be encoded using 973 * the Java platform's default charset (UTF-16) if it contains 974 * non-ASCII characters; otherwise, it is used as is. 975 * 976 * @param email A String. 977 * @return An Email. 978 * @throws EmailException Indicates an invalid email address 979 * @since 1.0 980 */ 981 public Email addBcc(String email) 982 throws EmailException 983 { 984 return this.addBcc(email, null); 985 } 986 987 /** 988 * Add an array of blind BCC recipients to the email. The email 989 * addresses will also be used as the personal name. 990 * The names will be encoded by the charset of 991 * {@link #setCharset(java.lang.String) setCharset()}. 992 * If it is not set, it will be encoded using 993 * the Java platform's default charset (UTF-16) if it contains 994 * non-ASCII characters; otherwise, it is used as is. 995 * 996 * @param emails A String array. 997 * @return An Email. 998 * @throws EmailException Indicates an invalid email address 999 * @since 1.3 1000 */ 1001 public Email addBcc(String... emails) 1002 throws EmailException 1003 { 1004 if (emails == null || emails.length == 0) 1005 { 1006 throw new EmailException("Address List provided was invalid"); 1007 } 1008 1009 for (String email : emails) 1010 { 1011 addBcc(email, null); 1012 } 1013 1014 return this; 1015 } 1016 1017 /** 1018 * Add a blind BCC recipient to the email using the specified address and 1019 * the specified personal name. 1020 * The name will be encoded by the charset of {@link #setCharset(java.lang.String) setCharset()}. 1021 * If it is not set, it will be encoded using 1022 * the Java platform's default charset (UTF-16) if it contains 1023 * non-ASCII characters; otherwise, it is used as is. 1024 * 1025 * @param email A String. 1026 * @param name A String. 1027 * @return An Email. 1028 * @throws EmailException Indicates an invalid email address 1029 * @since 1.0 1030 */ 1031 public Email addBcc(String email, String name) 1032 throws EmailException 1033 { 1034 return addBcc(email, name, this.charset); 1035 } 1036 1037 /** 1038 * Add a blind BCC recipient to the email using the specified address, 1039 * personal name, and charset encoding for the name. 1040 * 1041 * @param email A String. 1042 * @param name A String. 1043 * @param charset The charset to encode the name with. 1044 * @return An Email. 1045 * @throws EmailException Indicates an invalid email address 1046 * @since 1.1 1047 */ 1048 public Email addBcc(String email, String name, String charset) 1049 throws EmailException 1050 { 1051 this.bccList.add(createInternetAddress(email, name, charset)); 1052 return this; 1053 } 1054 1055 /** 1056 * Set a list of "BCC" addresses. All elements in the specified 1057 * <code>Collection</code> are expected to be of type 1058 * <code>java.mail.internet.InternetAddress</code>. 1059 * 1060 * @param aCollection collection of <code>InternetAddress</code> objects 1061 * @return An Email. 1062 * @throws EmailException Indicates an invalid email address 1063 * @see javax.mail.internet.InternetAddress 1064 * @since 1.0 1065 */ 1066 public Email setBcc(Collection<InternetAddress> aCollection) throws EmailException 1067 { 1068 if (aCollection == null || aCollection.isEmpty()) 1069 { 1070 throw new EmailException("Address List provided was invalid"); 1071 } 1072 1073 this.bccList = new ArrayList<InternetAddress>(aCollection); 1074 return this; 1075 } 1076 1077 /** 1078 * Add a reply to address to the email. The email 1079 * address will also be used as the personal name. 1080 * The name will be encoded by the charset of {@link #setCharset(java.lang.String) setCharset()}. 1081 * If it is not set, it will be encoded using 1082 * the Java platform's default charset (UTF-16) if it contains 1083 * non-ASCII characters; otherwise, it is used as is. 1084 * 1085 * @param email A String. 1086 * @return An Email. 1087 * @throws EmailException Indicates an invalid email address 1088 * @since 1.0 1089 */ 1090 public Email addReplyTo(String email) 1091 throws EmailException 1092 { 1093 return this.addReplyTo(email, null); 1094 } 1095 1096 /** 1097 * Add a reply to address to the email using the specified address and 1098 * the specified personal name. 1099 * The name will be encoded by the charset of {@link #setCharset(java.lang.String) setCharset()}. 1100 * If it is not set, it will be encoded using 1101 * the Java platform's default charset (UTF-16) if it contains 1102 * non-ASCII characters; otherwise, it is used as is. 1103 * 1104 * @param email A String. 1105 * @param name A String. 1106 * @return An Email. 1107 * @throws EmailException Indicates an invalid email address 1108 * @since 1.0 1109 */ 1110 public Email addReplyTo(String email, String name) 1111 throws EmailException 1112 { 1113 return addReplyTo(email, name, this.charset); 1114 } 1115 1116 /** 1117 * Add a reply to address to the email using the specified address, 1118 * personal name, and charset encoding for the name. 1119 * 1120 * @param email A String. 1121 * @param name A String. 1122 * @param charset The charset to encode the name with. 1123 * @return An Email. 1124 * @throws EmailException Indicates an invalid email address or charset. 1125 * @since 1.1 1126 */ 1127 public Email addReplyTo(String email, String name, String charset) 1128 throws EmailException 1129 { 1130 this.replyList.add(createInternetAddress(email, name, charset)); 1131 return this; 1132 } 1133 1134 /** 1135 * Set a list of reply to addresses. All elements in the specified 1136 * <code>Collection</code> are expected to be of type 1137 * <code>java.mail.internet.InternetAddress</code>. 1138 * 1139 * @param aCollection collection of <code>InternetAddress</code> objects 1140 * @return An Email. 1141 * @throws EmailException Indicates an invalid email address 1142 * @see javax.mail.internet.InternetAddress 1143 * @since 1.1 1144 */ 1145 public Email setReplyTo(Collection<InternetAddress> aCollection) throws EmailException 1146 { 1147 if (aCollection == null || aCollection.isEmpty()) 1148 { 1149 throw new EmailException("Address List provided was invalid"); 1150 } 1151 1152 this.replyList = new ArrayList<InternetAddress>(aCollection); 1153 return this; 1154 } 1155 1156 /** 1157 * Used to specify the mail headers. Example: 1158 * 1159 * X-Mailer: Sendmail, X-Priority: 1( highest ) 1160 * or 2( high ) 3( normal ) 4( low ) and 5( lowest ) 1161 * Disposition-Notification-To: user@domain.net 1162 * 1163 * @param map A Map. 1164 * @throws IllegalArgumentException if either of the provided header / value is null or empty 1165 * @since 1.0 1166 */ 1167 public void setHeaders(Map<String, String> map) 1168 { 1169 this.headers.clear(); 1170 1171 Iterator<Map.Entry<String, String>> iterKeyBad = map.entrySet().iterator(); 1172 1173 while (iterKeyBad.hasNext()) 1174 { 1175 Map.Entry<String, String> entry = iterKeyBad.next(); 1176 addHeader(entry.getKey(), entry.getValue()); 1177 } 1178 } 1179 1180 /** 1181 * Adds a header ( name, value ) to the headers Map. 1182 * 1183 * @param name A String with the name. 1184 * @param value A String with the value. 1185 * @since 1.0 1186 * @throws IllegalArgumentException if either {@code name} or {@code value} is null or empty 1187 */ 1188 public void addHeader(String name, String value) 1189 { 1190 if (EmailUtils.isEmpty(name)) 1191 { 1192 throw new IllegalArgumentException("name can not be null or empty"); 1193 } 1194 if (EmailUtils.isEmpty(value)) 1195 { 1196 throw new IllegalArgumentException("value can not be null or empty"); 1197 } 1198 1199 this.headers.put(name, value); 1200 } 1201 1202 /** 1203 * Set the email subject. 1204 * 1205 * @param aSubject A String. 1206 * @return An Email. 1207 * @since 1.0 1208 */ 1209 public Email setSubject(String aSubject) 1210 { 1211 this.subject = aSubject; 1212 return this; 1213 } 1214 1215 /** 1216 * Set the "bounce address" - the address to which undeliverable messages 1217 * will be returned. If this value is never set, then the message will be 1218 * sent to the address specified with the System property "mail.smtp.from", 1219 * or if that value is not set, then to the "from" address. 1220 * 1221 * @param email A String. 1222 * @return An Email. 1223 * @throws IllegalStateException when the mail session is already initialized 1224 * @since 1.0 1225 */ 1226 public Email setBounceAddress(String email) 1227 { 1228 checkSessionAlreadyInitialized(); 1229 this.bounceAddress = email; 1230 return this; 1231 } 1232 1233 1234 /** 1235 * Define the content of the mail. It should be overridden by the 1236 * subclasses. 1237 * 1238 * @param msg A String. 1239 * @return An Email. 1240 * @throws EmailException generic exception. 1241 * @since 1.0 1242 */ 1243 public abstract Email setMsg(String msg) throws EmailException; 1244 1245 /** 1246 * Does the work of actually building the MimeMessage. Please note that 1247 * a user rarely calls this method directly and only if he/she is 1248 * interested in the sending the underlying MimeMessage without 1249 * commons-email. 1250 * 1251 * @throws IllegalStateException if the MimeMessage was already built 1252 * @throws EmailException if there was an error. 1253 * @since 1.0 1254 */ 1255 public void buildMimeMessage() throws EmailException 1256 { 1257 if (this.message != null) 1258 { 1259 // [EMAIL-95] we assume that an email is not reused therefore invoking 1260 // buildMimeMessage() more than once is illegal. 1261 throw new IllegalStateException("The MimeMessage is already built."); 1262 } 1263 1264 try 1265 { 1266 this.message = this.createMimeMessage(this.getMailSession()); 1267 1268 if (EmailUtils.isNotEmpty(this.subject)) 1269 { 1270 if (EmailUtils.isNotEmpty(this.charset)) 1271 { 1272 this.message.setSubject(this.subject, this.charset); 1273 } 1274 else 1275 { 1276 this.message.setSubject(this.subject); 1277 } 1278 } 1279 1280 // update content type (and encoding) 1281 this.updateContentType(this.contentType); 1282 1283 if (this.content != null) 1284 { 1285 this.message.setContent(this.content, this.contentType); 1286 } 1287 else if (this.emailBody != null) 1288 { 1289 if (this.contentType == null) 1290 { 1291 this.message.setContent(this.emailBody); 1292 } 1293 else 1294 { 1295 this.message.setContent(this.emailBody, this.contentType); 1296 } 1297 } 1298 else 1299 { 1300 this.message.setContent("", Email.TEXT_PLAIN); 1301 } 1302 1303 if (this.fromAddress != null) 1304 { 1305 this.message.setFrom(this.fromAddress); 1306 } 1307 else 1308 { 1309 if (session.getProperty(MAIL_SMTP_FROM) == null) 1310 { 1311 throw new EmailException("From address required"); 1312 } 1313 } 1314 1315 if (this.toList.size() + this.ccList.size() + this.bccList.size() == 0) 1316 { 1317 throw new EmailException("At least one receiver address required"); 1318 } 1319 1320 if (this.toList.size() > 0) 1321 { 1322 this.message.setRecipients( 1323 Message.RecipientType.TO, 1324 this.toInternetAddressArray(this.toList)); 1325 } 1326 1327 if (this.ccList.size() > 0) 1328 { 1329 this.message.setRecipients( 1330 Message.RecipientType.CC, 1331 this.toInternetAddressArray(this.ccList)); 1332 } 1333 1334 if (this.bccList.size() > 0) 1335 { 1336 this.message.setRecipients( 1337 Message.RecipientType.BCC, 1338 this.toInternetAddressArray(this.bccList)); 1339 } 1340 1341 if (this.replyList.size() > 0) 1342 { 1343 this.message.setReplyTo( 1344 this.toInternetAddressArray(this.replyList)); 1345 } 1346 1347 1348 if (this.headers.size() > 0) 1349 { 1350 Iterator<String> iterHeaderKeys = this.headers.keySet().iterator(); 1351 while (iterHeaderKeys.hasNext()) 1352 { 1353 String name = iterHeaderKeys.next(); 1354 String value = headers.get(name); 1355 String foldedValue = createFoldedHeaderValue(name, value); 1356 this.message.addHeader(name, foldedValue); 1357 } 1358 } 1359 1360 if (this.message.getSentDate() == null) 1361 { 1362 this.message.setSentDate(getSentDate()); 1363 } 1364 1365 if (this.popBeforeSmtp) 1366 { 1367 Store store = session.getStore("pop3"); 1368 store.connect(this.popHost, this.popUsername, this.popPassword); 1369 } 1370 } 1371 catch (MessagingException me) 1372 { 1373 throw new EmailException(me); 1374 } 1375 } 1376 1377 /** 1378 * Sends the previously created MimeMessage to the SMTP server. 1379 * 1380 * @return the message id of the underlying MimeMessage 1381 * @throws IllegalArgumentException if the MimeMessage has not been created 1382 * @throws EmailException the sending failed 1383 */ 1384 public String sendMimeMessage() 1385 throws EmailException 1386 { 1387 EmailUtils.notNull(this.message, "MimeMessage has not been created yet"); 1388 1389 try 1390 { 1391 Transport.send(this.message); 1392 return this.message.getMessageID(); 1393 } 1394 catch (Throwable t) 1395 { 1396 String msg = "Sending the email to the following server failed : " 1397 + this.getHostName() 1398 + ":" 1399 + this.getSmtpPort(); 1400 1401 throw new EmailException(msg, t); 1402 } 1403 } 1404 1405 /** 1406 * Returns the internal MimeMessage. Please not that the 1407 * MimeMessage is build by the buildMimeMessage() method. 1408 * 1409 * @return the MimeMessage 1410 */ 1411 public MimeMessage getMimeMessage() 1412 { 1413 return this.message; 1414 } 1415 1416 /** 1417 * Sends the email. Internally we build a MimeMessage 1418 * which is afterwards sent to the SMTP server. 1419 * 1420 * @return the message id of the underlying MimeMessage 1421 * @throws IllegalStateException if the MimeMessage was already built, ie {@link #buildMimeMessage()} 1422 * was already called 1423 * @throws EmailException the sending failed 1424 */ 1425 public String send() throws EmailException 1426 { 1427 this.buildMimeMessage(); 1428 return this.sendMimeMessage(); 1429 } 1430 1431 /** 1432 * Sets the sent date for the email. The sent date will default to the 1433 * current date if not explicitly set. 1434 * 1435 * @param date Date to use as the sent date on the email 1436 * @since 1.0 1437 */ 1438 public void setSentDate(Date date) 1439 { 1440 if (date != null) 1441 { 1442 // create a separate instance to keep findbugs happy 1443 this.sentDate = new Date(date.getTime()); 1444 } 1445 } 1446 1447 /** 1448 * Gets the sent date for the email. 1449 * 1450 * @return date to be used as the sent date for the email 1451 * @since 1.0 1452 */ 1453 public Date getSentDate() 1454 { 1455 if (this.sentDate == null) 1456 { 1457 return new Date(); 1458 } 1459 return new Date(this.sentDate.getTime()); 1460 } 1461 1462 /** 1463 * Gets the subject of the email. 1464 * 1465 * @return email subject 1466 */ 1467 public String getSubject() 1468 { 1469 return this.subject; 1470 } 1471 1472 /** 1473 * Gets the sender of the email. 1474 * 1475 * @return from address 1476 */ 1477 public InternetAddress getFromAddress() 1478 { 1479 return this.fromAddress; 1480 } 1481 1482 /** 1483 * Gets the host name of the SMTP server, 1484 * 1485 * @return host name 1486 */ 1487 public String getHostName() 1488 { 1489 if (this.session != null) 1490 { 1491 return this.session.getProperty(MAIL_HOST); 1492 } 1493 else if (EmailUtils.isNotEmpty(this.hostName)) 1494 { 1495 return this.hostName; 1496 } 1497 return null; 1498 } 1499 1500 /** 1501 * Gets the listening port of the SMTP server. 1502 * 1503 * @return smtp port 1504 */ 1505 public String getSmtpPort() 1506 { 1507 if (this.session != null) 1508 { 1509 return this.session.getProperty(MAIL_PORT); 1510 } 1511 else if (EmailUtils.isNotEmpty(this.smtpPort)) 1512 { 1513 return this.smtpPort; 1514 } 1515 return null; 1516 } 1517 1518 /** 1519 * Gets whether the client is configured to require STARTTLS. 1520 * 1521 * @return true if using STARTTLS for authentication, false otherwise 1522 * @since 1.3 1523 */ 1524 public boolean isStartTLSRequired() 1525 { 1526 return this.startTlsRequired; 1527 } 1528 1529 /** 1530 * Gets whether the client is configured to try to enable STARTTLS. 1531 * 1532 * @return true if using STARTTLS for authentication, false otherwise 1533 * @since 1.3 1534 */ 1535 public boolean isStartTLSEnabled() 1536 { 1537 return this.startTlsEnabled || tls; 1538 } 1539 1540 /** 1541 * Gets whether the client is configured to try to enable STARTTLS. 1542 * See EMAIL-105 for reason of deprecation. 1543 * 1544 * @deprecated since 1.3, use isStartTLSEnabled() instead 1545 * @return true if using STARTTLS for authentication, false otherwise 1546 * @since 1.1 1547 */ 1548 @Deprecated 1549 public boolean isTLS() 1550 { 1551 return isStartTLSEnabled(); 1552 } 1553 1554 /** 1555 * Utility to copy List of known InternetAddress objects into an 1556 * array. 1557 * 1558 * @param list A List. 1559 * @return An InternetAddress[]. 1560 * @since 1.0 1561 */ 1562 protected InternetAddress[] toInternetAddressArray(List<InternetAddress> list) 1563 { 1564 InternetAddress[] ia = list.toArray(new InternetAddress[list.size()]); 1565 1566 return ia; 1567 } 1568 1569 /** 1570 * Set details regarding "pop3 before smtp" authentication. 1571 * 1572 * @param newPopBeforeSmtp Whether or not to log into pop3 server before sending mail. 1573 * @param newPopHost The pop3 host to use. 1574 * @param newPopUsername The pop3 username. 1575 * @param newPopPassword The pop3 password. 1576 * @since 1.0 1577 */ 1578 public void setPopBeforeSmtp( 1579 boolean newPopBeforeSmtp, 1580 String newPopHost, 1581 String newPopUsername, 1582 String newPopPassword) 1583 { 1584 this.popBeforeSmtp = newPopBeforeSmtp; 1585 this.popHost = newPopHost; 1586 this.popUsername = newPopUsername; 1587 this.popPassword = newPopPassword; 1588 } 1589 1590 /** 1591 * Returns whether SSL/TLS encryption for the transport is currently enabled (SMTPS/POPS). 1592 * See EMAIL-105 for reason of deprecation. 1593 * 1594 * @deprecated since 1.3, use isSSLOnConnect() instead 1595 * @return true if SSL enabled for the transport 1596 */ 1597 @Deprecated 1598 public boolean isSSL() 1599 { 1600 return isSSLOnConnect(); 1601 } 1602 1603 /** 1604 * Returns whether SSL/TLS encryption for the transport is currently enabled (SMTPS/POPS). 1605 * 1606 * @return true if SSL enabled for the transport 1607 * @since 1.3 1608 */ 1609 public boolean isSSLOnConnect() 1610 { 1611 return sslOnConnect || ssl; 1612 } 1613 1614 /** 1615 * Sets whether SSL/TLS encryption should be enabled for the SMTP transport upon connection (SMTPS/POPS). 1616 * See EMAIL-105 for reason of deprecation. 1617 * 1618 * @deprecated since 1.3, use setSSLOnConnect() instead 1619 * @param ssl whether to enable the SSL transport 1620 */ 1621 @Deprecated 1622 public void setSSL(boolean ssl) 1623 { 1624 setSSLOnConnect(ssl); 1625 } 1626 1627 /** 1628 * Sets whether SSL/TLS encryption should be enabled for the SMTP transport upon connection (SMTPS/POPS). 1629 * 1630 * @param ssl whether to enable the SSL transport 1631 * @return An Email. 1632 * @since 1.3 1633 */ 1634 public Email setSSLOnConnect(boolean ssl) 1635 { 1636 checkSessionAlreadyInitialized(); 1637 this.sslOnConnect = ssl; 1638 this.ssl = ssl; 1639 return this; 1640 } 1641 1642 /** 1643 * Is the server identity checked as specified by RFC 2595 1644 * 1645 * @return true if the server identity is checked 1646 * @since 1.3 1647 */ 1648 public boolean isSSLCheckServerIdentity() 1649 { 1650 return sslCheckServerIdentity; 1651 } 1652 1653 /** 1654 * Sets whether the server identity is checked as specified by RFC 2595 1655 * 1656 * @param sslCheckServerIdentity whether to enable server identity check 1657 * @return An Email. 1658 * @since 1.3 1659 */ 1660 public Email setSSLCheckServerIdentity(boolean sslCheckServerIdentity) 1661 { 1662 this.sslCheckServerIdentity = sslCheckServerIdentity; 1663 return this; 1664 } 1665 1666 /** 1667 * Returns the current SSL port used by the SMTP transport. 1668 * 1669 * @return the current SSL port used by the SMTP transport 1670 */ 1671 public String getSslSmtpPort() 1672 { 1673 if (this.session != null) 1674 { 1675 return this.session.getProperty(MAIL_SMTP_SOCKET_FACTORY_PORT); 1676 } 1677 else if (EmailUtils.isNotEmpty(this.sslSmtpPort)) 1678 { 1679 return this.sslSmtpPort; 1680 } 1681 return null; 1682 } 1683 1684 /** 1685 * Sets the SSL port to use for the SMTP transport. Defaults to the standard 1686 * port, 465. 1687 * 1688 * @param sslSmtpPort the SSL port to use for the SMTP transport 1689 */ 1690 public void setSslSmtpPort(String sslSmtpPort) 1691 { 1692 checkSessionAlreadyInitialized(); 1693 this.sslSmtpPort = sslSmtpPort; 1694 } 1695 1696 /** 1697 * Get the list of "To" addresses. 1698 * 1699 * @return List addresses 1700 */ 1701 public List<InternetAddress> getToAddresses() 1702 { 1703 return this.toList; 1704 } 1705 1706 /** 1707 * Get the list of "CC" addresses. 1708 * 1709 * @return List addresses 1710 */ 1711 public List<InternetAddress> getCcAddresses() 1712 { 1713 return this.ccList; 1714 } 1715 1716 /** 1717 * Get the list of "Bcc" addresses. 1718 * 1719 * @return List addresses 1720 */ 1721 public List<InternetAddress> getBccAddresses() 1722 { 1723 return this.bccList; 1724 } 1725 1726 /** 1727 * Get the list of "Reply-To" addresses. 1728 * 1729 * @return List addresses 1730 */ 1731 public List<InternetAddress> getReplyToAddresses() 1732 { 1733 return this.replyList; 1734 } 1735 1736 /** 1737 * Get the socket connection timeout value in milliseconds. 1738 * 1739 * @return the timeout in milliseconds. 1740 * @since 1.2 1741 */ 1742 public int getSocketConnectionTimeout() 1743 { 1744 return this.socketConnectionTimeout; 1745 } 1746 1747 /** 1748 * Set the socket connection timeout value in milliseconds. 1749 * Default is a 60 second timeout. 1750 * 1751 * @param socketConnectionTimeout the connection timeout 1752 * @since 1.2 1753 */ 1754 public void setSocketConnectionTimeout(int socketConnectionTimeout) 1755 { 1756 checkSessionAlreadyInitialized(); 1757 this.socketConnectionTimeout = socketConnectionTimeout; 1758 } 1759 1760 /** 1761 * Get the socket I/O timeout value in milliseconds. 1762 * 1763 * @return the socket I/O timeout 1764 * @since 1.2 1765 */ 1766 public int getSocketTimeout() 1767 { 1768 return this.socketTimeout; 1769 } 1770 1771 /** 1772 * Set the socket I/O timeout value in milliseconds. 1773 * Default is 60 second timeout. 1774 * 1775 * @param socketTimeout the socket I/O timeout 1776 * @since 1.2 1777 */ 1778 public void setSocketTimeout(int socketTimeout) 1779 { 1780 checkSessionAlreadyInitialized(); 1781 this.socketTimeout = socketTimeout; 1782 } 1783 1784 /** 1785 * Factory method to create a customized MimeMessage which can be 1786 * implemented by a derived class, e.g. to set the message id. 1787 * 1788 * @param aSession mail session to be used 1789 * @return the newly created message 1790 */ 1791 protected MimeMessage createMimeMessage(Session aSession) 1792 { 1793 return new MimeMessage(aSession); 1794 } 1795 1796 /** 1797 * Create a folded header value containing 76 character chunks. 1798 * 1799 * @param name the name of the header 1800 * @param value the value of the header 1801 * @return the folded header value 1802 * @throws IllegalArgumentException if either the name or value is null or empty 1803 */ 1804 private String createFoldedHeaderValue(String name, Object value) 1805 { 1806 String result; 1807 1808 if (EmailUtils.isEmpty(name)) 1809 { 1810 throw new IllegalArgumentException("name can not be null or empty"); 1811 } 1812 if (value == null || EmailUtils.isEmpty(value.toString())) 1813 { 1814 throw new IllegalArgumentException("value can not be null or empty"); 1815 } 1816 1817 try 1818 { 1819 result = MimeUtility.fold(name.length() + 2, MimeUtility.encodeText(value.toString(), this.charset, null)); 1820 } 1821 catch (UnsupportedEncodingException e) 1822 { 1823 result = value.toString(); 1824 } 1825 1826 return result; 1827 } 1828 1829 /** 1830 * Creates a InternetAddress. 1831 * 1832 * @param email An email address. 1833 * @param name A name. 1834 * @param charsetName The name of the charset to encode the name with. 1835 * @return An internet address. 1836 * @throws EmailException Thrown when the supplied address, name or charset were invalid. 1837 */ 1838 private InternetAddress createInternetAddress(String email, String name, String charsetName) 1839 throws EmailException 1840 { 1841 InternetAddress address = null; 1842 1843 try 1844 { 1845 address = new InternetAddress(email); 1846 1847 // check name input 1848 if (EmailUtils.isNotEmpty(name)) 1849 { 1850 // check charset input. 1851 if (EmailUtils.isEmpty(charsetName)) 1852 { 1853 address.setPersonal(name); 1854 } 1855 else 1856 { 1857 // canonicalize the charset name and make sure 1858 // the current platform supports it. 1859 Charset set = Charset.forName(charsetName); 1860 address.setPersonal(name, set.name()); 1861 } 1862 } 1863 1864 // run sanity check on new InternetAddress object; if this fails 1865 // it will throw AddressException. 1866 address.validate(); 1867 } 1868 catch (AddressException e) 1869 { 1870 throw new EmailException(e); 1871 } 1872 catch (UnsupportedEncodingException e) 1873 { 1874 throw new EmailException(e); 1875 } 1876 return address; 1877 } 1878 1879 /** 1880 * When a mail session is already initialized setting the 1881 * session properties has no effect. In order to flag the 1882 * problem throw an IllegalStateException. 1883 * 1884 * @throws IllegalStateException when the mail session is already initialized 1885 */ 1886 private void checkSessionAlreadyInitialized() 1887 { 1888 if (this.session != null) 1889 { 1890 throw new IllegalStateException("The mail session is already initialized"); 1891 } 1892 } 1893}