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.List; 026import java.util.Map; 027import java.util.Properties; 028 029import javax.mail.Authenticator; 030import javax.mail.Message; 031import javax.mail.MessagingException; 032import javax.mail.Session; 033import javax.mail.Store; 034import javax.mail.Transport; 035import javax.mail.internet.AddressException; 036import javax.mail.internet.InternetAddress; 037import javax.mail.internet.MimeMessage; 038import javax.mail.internet.MimeMultipart; 039import javax.mail.internet.MimeUtility; 040import javax.naming.Context; 041import javax.naming.InitialContext; 042import 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. 048 * <p> 049 * Subclasses are responsible for setting the message body. 050 * 051 * @since 1.0 052 * @version $Id: Email.java 1606709 2014-06-30 12:26:06Z ggregory $ 053 */ 054public abstract class Email 055{ 056 /** @deprecated since 1.3, use {@link EmailConstants#SENDER_EMAIL} instead */ 057 @Deprecated 058 public static final String SENDER_EMAIL = EmailConstants.SENDER_EMAIL; 059 060 /** @deprecated since 1.3, use {@link EmailConstants#SENDER_NAME} instead */ 061 @Deprecated 062 public static final String SENDER_NAME = EmailConstants.SENDER_NAME; 063 064 /** @deprecated since 1.3, use {@link EmailConstants#RECEIVER_EMAIL} instead */ 065 @Deprecated 066 public static final String RECEIVER_EMAIL = EmailConstants.RECEIVER_EMAIL; 067 068 /** @deprecated since 1.3, use {@link EmailConstants#RECEIVER_NAME} instead */ 069 @Deprecated 070 public static final String RECEIVER_NAME = EmailConstants.RECEIVER_NAME; 071 072 /** @deprecated since 1.3, use {@link EmailConstants#EMAIL_SUBJECT} instead */ 073 @Deprecated 074 public static final String EMAIL_SUBJECT = EmailConstants.EMAIL_SUBJECT; 075 076 /** @deprecated since 1.3, use {@link EmailConstants#EMAIL_BODY} instead */ 077 @Deprecated 078 public static final String EMAIL_BODY = EmailConstants.EMAIL_BODY; 079 080 /** @deprecated since 1.3, use {@link EmailConstants#CONTENT_TYPE} instead */ 081 @Deprecated 082 public static final String CONTENT_TYPE = EmailConstants.CONTENT_TYPE; 083 084 /** @deprecated since 1.3, use {@link EmailConstants#ATTACHMENTS} instead */ 085 @Deprecated 086 public static final String ATTACHMENTS = EmailConstants.ATTACHMENTS; 087 088 /** @deprecated since 1.3, use {@link EmailConstants#FILE_SERVER} instead */ 089 @Deprecated 090 public static final String FILE_SERVER = EmailConstants.FILE_SERVER; 091 092 /** @deprecated since 1.3, use {@link EmailConstants#KOI8_R} instead */ 093 @Deprecated 094 public static final String KOI8_R = EmailConstants.KOI8_R; 095 096 /** @deprecated since 1.3, use {@link EmailConstants#ISO_8859_1} instead */ 097 @Deprecated 098 public static final String ISO_8859_1 = EmailConstants.ISO_8859_1; 099 100 /** @deprecated since 1.3, use {@link EmailConstants#US_ASCII} instead */ 101 @Deprecated 102 public static final String US_ASCII = EmailConstants.US_ASCII; 103 104 /** @deprecated since 1.3, use {@link EmailConstants#MAIL_DEBUG} instead */ 105 @Deprecated 106 public static final String MAIL_DEBUG = EmailConstants.MAIL_DEBUG; 107 108 /** @deprecated since 1.3, use {@link EmailConstants#MAIL_HOST} instead */ 109 @Deprecated 110 public static final String MAIL_HOST = EmailConstants.MAIL_HOST; 111 112 /** @deprecated since 1.3, use {@link EmailConstants#MAIL_PORT} instead */ 113 @Deprecated 114 public static final String MAIL_PORT = EmailConstants.MAIL_PORT; 115 116 /** @deprecated since 1.3, use {@link EmailConstants#MAIL_SMTP_FROM} instead */ 117 @Deprecated 118 public static final String MAIL_SMTP_FROM = EmailConstants.MAIL_SMTP_FROM; 119 120 /** @deprecated since 1.3, use {@link EmailConstants#MAIL_SMTP_AUTH} instead */ 121 @Deprecated 122 public static final String MAIL_SMTP_AUTH = EmailConstants.MAIL_SMTP_AUTH; 123 124 /** @deprecated since 1.3, use {@link EmailConstants#MAIL_SMTP_USER} instead */ 125 @Deprecated 126 public static final String MAIL_SMTP_USER = EmailConstants.MAIL_SMTP_USER; 127 128 /** @deprecated since 1.3, use {@link EmailConstants#MAIL_SMTP_PASSWORD} instead */ 129 @Deprecated 130 public static final String MAIL_SMTP_PASSWORD = EmailConstants.MAIL_SMTP_PASSWORD; 131 132 /** @deprecated since 1.3, use {@link EmailConstants#MAIL_TRANSPORT_PROTOCOL} instead */ 133 @Deprecated 134 public static final String MAIL_TRANSPORT_PROTOCOL = EmailConstants.MAIL_TRANSPORT_PROTOCOL; 135 136 /** @deprecated since 1.3, use {@link EmailConstants#SMTP} instead */ 137 @Deprecated 138 public static final String SMTP = EmailConstants.SMTP; 139 140 /** @deprecated since 1.3, use {@link EmailConstants#TEXT_HTML} instead */ 141 @Deprecated 142 public static final String TEXT_HTML = EmailConstants.TEXT_HTML; 143 144 /** @deprecated since 1.3, use {@link EmailConstants#TEXT_PLAIN} instead */ 145 @Deprecated 146 public static final String TEXT_PLAIN = EmailConstants.TEXT_PLAIN; 147 148 /** @deprecated since 1.3, use {@link EmailConstants#MAIL_TRANSPORT_TLS} instead */ 149 @Deprecated 150 public static final String MAIL_TRANSPORT_TLS = EmailConstants.MAIL_TRANSPORT_TLS; 151 152 /** @deprecated since 1.3, use {@link EmailConstants#MAIL_SMTP_SOCKET_FACTORY_FALLBACK} instead */ 153 @Deprecated 154 public static final String MAIL_SMTP_SOCKET_FACTORY_FALLBACK = EmailConstants.MAIL_SMTP_SOCKET_FACTORY_FALLBACK; 155 156 /** @deprecated since 1.3, use {@link EmailConstants#MAIL_SMTP_SOCKET_FACTORY_CLASS} instead */ 157 @Deprecated 158 public static final String MAIL_SMTP_SOCKET_FACTORY_CLASS = EmailConstants.MAIL_SMTP_SOCKET_FACTORY_CLASS; 159 160 /** @deprecated since 1.3, use {@link EmailConstants#MAIL_SMTP_SOCKET_FACTORY_PORT} instead */ 161 @Deprecated 162 public static final String MAIL_SMTP_SOCKET_FACTORY_PORT = EmailConstants.MAIL_SMTP_SOCKET_FACTORY_PORT; 163 164 /** @deprecated since 1.3, use {@link EmailConstants#MAIL_SMTP_CONNECTIONTIMEOUT} instead */ 165 @Deprecated 166 public static final String MAIL_SMTP_CONNECTIONTIMEOUT = EmailConstants.MAIL_SMTP_CONNECTIONTIMEOUT; 167 168 /** @deprecated since 1.3, use {@link EmailConstants#MAIL_SMTP_TIMEOUT} instead */ 169 @Deprecated 170 public static final String MAIL_SMTP_TIMEOUT = EmailConstants.MAIL_SMTP_TIMEOUT; 171 172 /** The email message to send. */ 173 protected MimeMessage message; 174 175 /** The charset to use for this message. */ 176 protected String charset; 177 178 /** The Address of the sending party, mandatory. */ 179 protected InternetAddress fromAddress; 180 181 /** The Subject. */ 182 protected String subject; 183 184 /** An attachment. */ 185 protected MimeMultipart emailBody; 186 187 /** The content. */ 188 protected Object content; 189 190 /** The content type. */ 191 protected String contentType; 192 193 /** Set session debugging on or off. */ 194 protected boolean debug; 195 196 /** Sent date. */ 197 protected Date sentDate; 198 199 /** 200 * Instance of an <code>Authenticator</code> object that will be used 201 * when authentication is requested from the mail server. 202 */ 203 protected Authenticator authenticator; 204 205 /** 206 * The hostname of the mail server with which to connect. If null will try 207 * to get property from system.properties. If still null, quit. 208 */ 209 protected String hostName; 210 211 /** 212 * The port number of the mail server to connect to. 213 * Defaults to the standard port ( 25 ). 214 */ 215 protected String smtpPort = "25"; 216 217 /** 218 * The port number of the SSL enabled SMTP server; 219 * defaults to the standard port, 465. 220 */ 221 protected String sslSmtpPort = "465"; 222 223 /** List of "to" email addresses. */ 224 protected List<InternetAddress> toList = new ArrayList<InternetAddress>(); 225 226 /** List of "cc" email addresses. */ 227 protected List<InternetAddress> ccList = new ArrayList<InternetAddress>(); 228 229 /** List of "bcc" email addresses. */ 230 protected List<InternetAddress> bccList = new ArrayList<InternetAddress>(); 231 232 /** List of "replyTo" email addresses. */ 233 protected List<InternetAddress> replyList = new ArrayList<InternetAddress>(); 234 235 /** 236 * Address to which undeliverable mail should be sent. 237 * Because this is handled by JavaMail as a String property 238 * in the mail session, this property is of type <code>String</code> 239 * rather than <code>InternetAddress</code>. 240 */ 241 protected String bounceAddress; 242 243 /** 244 * Used to specify the mail headers. Example: 245 * 246 * X-Mailer: Sendmail, X-Priority: 1( highest ) 247 * or 2( high ) 3( normal ) 4( low ) and 5( lowest ) 248 * Disposition-Notification-To: user@domain.net 249 */ 250 protected Map<String, String> headers = new HashMap<String, String>(); 251 252 /** 253 * Used to determine whether to use pop3 before smtp, and if so the settings. 254 */ 255 protected boolean popBeforeSmtp; 256 257 /** the host name of the pop3 server. */ 258 protected String popHost; 259 260 /** the user name to log into the pop3 server. */ 261 protected String popUsername; 262 263 /** the password to log into the pop3 server. */ 264 protected String popPassword; 265 266 /** 267 * Does server require TLS encryption for authentication? 268 * @deprecated since 1.3, use setStartTLSEnabled() instead 269 */ 270 @Deprecated 271 protected boolean tls; 272 273 /** 274 * Does the current transport use SSL/TLS encryption upon connection? 275 * @deprecated since 1.3, use setSSLOnConnect() instead 276 */ 277 @Deprecated 278 protected boolean ssl; 279 280 /** socket I/O timeout value in milliseconds. */ 281 protected int socketTimeout = EmailConstants.SOCKET_TIMEOUT_MS; 282 283 /** socket connection timeout value in milliseconds. */ 284 protected int socketConnectionTimeout = EmailConstants.SOCKET_TIMEOUT_MS; 285 286 /** 287 * If true, enables the use of the STARTTLS command (if supported by 288 * the server) to switch the connection to a TLS-protected connection 289 * before issuing any login commands. Note that an appropriate trust 290 * store must configured so that the client will trust the server's 291 * certificate. 292 * Defaults to false. 293 */ 294 private boolean startTlsEnabled; 295 296 /** 297 * If true, requires the use of the STARTTLS command. If the server doesn't 298 * support the STARTTLS command, or the command fails, the connect method 299 * will fail. 300 * Defaults to false. 301 */ 302 private boolean startTlsRequired; 303 304 /** does the current transport use SSL/TLS encryption upon connection? */ 305 private boolean sslOnConnect; 306 307 /** 308 * If set to true, check the server identity as specified by RFC 2595. These 309 * additional checks based on the content of the server's certificate are 310 * intended to prevent man-in-the-middle attacks. 311 * Defaults to false. 312 */ 313 private boolean sslCheckServerIdentity; 314 315 /** 316 * If set to true, and a message has some valid and some invalid addresses, send the message anyway, 317 * reporting the partial failure with a SendFailedException. 318 * If set to false (the default), the message is not sent to any of the recipients 319 * if there is an invalid recipient address. 320 * Defaults to false. 321 */ 322 private boolean sendPartial; 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(final 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(final String userName, final 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(final 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(final String newCharset) 383 { 384 final 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(final MimeMultipart aMimeMultipart) 395 { 396 this.emailBody = aMimeMultipart; 397 } 398 399 /** 400 * Set the content and contentType. 401 * 402 * @param aObject aObject 403 * @param aContentType aContentType 404 * @since 1.0 405 */ 406 public void setContent(final Object aObject, final 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 final 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 final 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 final 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(final 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(final 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(final 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(final 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(final 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(final Session aSession) 557 { 558 EmailUtils.notNull(aSession, "no mail session supplied"); 559 560 final Properties sessionProperties = aSession.getProperties(); 561 final String auth = sessionProperties.getProperty(MAIL_SMTP_AUTH); 562 563 if ("true".equalsIgnoreCase(auth)) 564 { 565 final String userName = sessionProperties.getProperty(MAIL_SMTP_USER); 566 final 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(final 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 final 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 properties.setProperty(EmailConstants.MAIL_SMTP_SEND_PARTIAL, 652 isSendPartial() ? "true" : "false"); 653 properties.setProperty(EmailConstants.MAIL_SMTPS_SEND_PARTIAL, 654 isSendPartial() ? "true" : "false"); 655 656 if (this.authenticator != null) 657 { 658 properties.setProperty(MAIL_SMTP_AUTH, "true"); 659 } 660 661 if (isSSLOnConnect()) 662 { 663 properties.setProperty(MAIL_PORT, this.sslSmtpPort); 664 properties.setProperty(MAIL_SMTP_SOCKET_FACTORY_PORT, this.sslSmtpPort); 665 properties.setProperty(MAIL_SMTP_SOCKET_FACTORY_CLASS, "javax.net.ssl.SSLSocketFactory"); 666 properties.setProperty(MAIL_SMTP_SOCKET_FACTORY_FALLBACK, "false"); 667 } 668 669 if ((isSSLOnConnect() || isStartTLSEnabled()) && isSSLCheckServerIdentity()) 670 { 671 properties.setProperty(EmailConstants.MAIL_SMTP_SSL_CHECKSERVERIDENTITY, "true"); 672 } 673 674 if (this.bounceAddress != null) 675 { 676 properties.setProperty(MAIL_SMTP_FROM, this.bounceAddress); 677 } 678 679 if (this.socketTimeout > 0) 680 { 681 properties.setProperty(MAIL_SMTP_TIMEOUT, Integer.toString(this.socketTimeout)); 682 } 683 684 if (this.socketConnectionTimeout > 0) 685 { 686 properties.setProperty(MAIL_SMTP_CONNECTIONTIMEOUT, Integer.toString(this.socketConnectionTimeout)); 687 } 688 689 // changed this (back) to getInstance due to security exceptions 690 // caused when testing using maven 691 this.session = Session.getInstance(properties, this.authenticator); 692 } 693 return this.session; 694 } 695 696 /** 697 * Set the FROM field of the email to use the specified address. The email 698 * address will also be used as the personal name. 699 * The name will be encoded by the charset of {@link #setCharset(java.lang.String) setCharset()}. 700 * If it is not set, it will be encoded using 701 * the Java platform's default charset (UTF-16) if it contains 702 * non-ASCII characters; otherwise, it is used as is. 703 * 704 * @param email A String. 705 * @return An Email. 706 * @throws EmailException Indicates an invalid email address. 707 * @since 1.0 708 */ 709 public Email setFrom(final String email) 710 throws EmailException 711 { 712 return setFrom(email, null); 713 } 714 715 /** 716 * Set the FROM field of the email to use the specified address and the 717 * specified personal name. 718 * The name will be encoded by the charset of {@link #setCharset(java.lang.String) setCharset()}. 719 * If it is not set, it will be encoded using 720 * the Java platform's default charset (UTF-16) if it contains 721 * non-ASCII characters; otherwise, it is used as is. 722 * 723 * @param email A String. 724 * @param name A String. 725 * @return An Email. 726 * @throws EmailException Indicates an invalid email address. 727 * @since 1.0 728 */ 729 public Email setFrom(final String email, final String name) 730 throws EmailException 731 { 732 return setFrom(email, name, this.charset); 733 } 734 735 /** 736 * Set the FROM field of the email to use the specified address, personal 737 * name, and charset encoding for the name. 738 * 739 * @param email A String. 740 * @param name A String. 741 * @param charset The charset to encode the name with. 742 * @return An Email. 743 * @throws EmailException Indicates an invalid email address or charset. 744 * @since 1.1 745 */ 746 public Email setFrom(final String email, final String name, final String charset) 747 throws EmailException 748 { 749 this.fromAddress = createInternetAddress(email, name, charset); 750 return this; 751 } 752 753 /** 754 * Add a recipient TO 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 757 * {@link #setCharset(java.lang.String) setCharset()}. 758 * If it is not set, it will be encoded using 759 * the Java platform's default charset (UTF-16) if it contains 760 * non-ASCII characters; otherwise, it is used as is. 761 * 762 * @param email A String. 763 * @return An Email. 764 * @throws EmailException Indicates an invalid email address. 765 * @since 1.0 766 */ 767 public Email addTo(final String email) 768 throws EmailException 769 { 770 return addTo(email, null); 771 } 772 773 /** 774 * Add a list of TO recipients to the email. The email 775 * addresses will also be used as the personal names. 776 * The names will be encoded by the charset of 777 * {@link #setCharset(java.lang.String) setCharset()}. 778 * If it is not set, it will be encoded using 779 * the Java platform's default charset (UTF-16) if it contains 780 * non-ASCII characters; otherwise, it is used as is. 781 * 782 * @param emails A String array. 783 * @return An Email. 784 * @throws EmailException Indicates an invalid email address. 785 * @since 1.3 786 */ 787 public Email addTo(final String... emails) 788 throws EmailException 789 { 790 if (emails == null || emails.length == 0) 791 { 792 throw new EmailException("Address List provided was invalid"); 793 } 794 795 for (final String email : emails) 796 { 797 addTo(email, null); 798 } 799 800 return this; 801 } 802 803 /** 804 * Add a recipient TO to the email using the specified address and the 805 * specified personal name. 806 * The name will be encoded by the charset of 807 * {@link #setCharset(java.lang.String) setCharset()}. 808 * If it is not set, it will be encoded using 809 * the Java platform's default charset (UTF-16) if it contains 810 * non-ASCII characters; otherwise, it is used as is. 811 * 812 * @param email A String. 813 * @param name A String. 814 * @return An Email. 815 * @throws EmailException Indicates an invalid email address. 816 * @since 1.0 817 */ 818 public Email addTo(final String email, final String name) 819 throws EmailException 820 { 821 return addTo(email, name, this.charset); 822 } 823 824 /** 825 * Add a recipient TO to the email using the specified address, personal 826 * name, and charset encoding for the name. 827 * 828 * @param email A String. 829 * @param name A String. 830 * @param charset The charset to encode the name with. 831 * @return An Email. 832 * @throws EmailException Indicates an invalid email address or charset. 833 * @since 1.1 834 */ 835 public Email addTo(final String email, final String name, final String charset) 836 throws EmailException 837 { 838 this.toList.add(createInternetAddress(email, name, charset)); 839 return this; 840 } 841 842 /** 843 * Set a list of "TO" addresses. All elements in the specified 844 * <code>Collection</code> are expected to be of type 845 * <code>java.mail.internet.InternetAddress</code>. 846 * 847 * @param aCollection collection of <code>InternetAddress</code> objects. 848 * @return An Email. 849 * @throws EmailException Indicates an invalid email address. 850 * @see javax.mail.internet.InternetAddress 851 * @since 1.0 852 */ 853 public Email setTo(final Collection<InternetAddress> aCollection) throws EmailException 854 { 855 if (aCollection == null || aCollection.isEmpty()) 856 { 857 throw new EmailException("Address List provided was invalid"); 858 } 859 860 this.toList = new ArrayList<InternetAddress>(aCollection); 861 return this; 862 } 863 864 /** 865 * Add a recipient CC to the email. The email 866 * address will also be used as the personal name. 867 * The name will be encoded by the charset of {@link #setCharset(java.lang.String) setCharset()}. 868 * If it is not set, it will be encoded using 869 * the Java platform's default charset (UTF-16) if it contains 870 * non-ASCII characters; otherwise, it is used as is. 871 * 872 * @param email A String. 873 * @return An Email. 874 * @throws EmailException Indicates an invalid email address. 875 * @since 1.0 876 */ 877 public Email addCc(final String email) 878 throws EmailException 879 { 880 return this.addCc(email, null); 881 } 882 883 /** 884 * Add an array of CC recipients to the email. The email 885 * addresses will also be used as the personal name. 886 * The names will be encoded by the charset of 887 * {@link #setCharset(java.lang.String) setCharset()}. 888 * If it is not set, it will be encoded using 889 * the Java platform's default charset (UTF-16) if it contains 890 * non-ASCII characters; otherwise, it is used as is. 891 * 892 * @param emails A String array. 893 * @return An Email. 894 * @throws EmailException Indicates an invalid email address. 895 * @since 1.3 896 */ 897 public Email addCc(final String... emails) 898 throws EmailException 899 { 900 if (emails == null || emails.length == 0) 901 { 902 throw new EmailException("Address List provided was invalid"); 903 } 904 905 for (final String email : emails) 906 { 907 addCc(email, null); 908 } 909 910 return this; 911 } 912 913 /** 914 * Add a recipient CC to the email using the specified address and the 915 * specified personal name. 916 * The name will be encoded by the charset of {@link #setCharset(java.lang.String) setCharset()}. 917 * If it is not set, it will be encoded using 918 * the Java platform's default charset (UTF-16) if it contains 919 * non-ASCII characters; otherwise, it is used as is. 920 * 921 * @param email A String. 922 * @param name A String. 923 * @return An Email. 924 * @throws EmailException Indicates an invalid email address. 925 * @since 1.0 926 */ 927 public Email addCc(final String email, final String name) 928 throws EmailException 929 { 930 return addCc(email, name, this.charset); 931 } 932 933 /** 934 * Add a recipient CC to the email using the specified address, personal 935 * name, and charset encoding for the name. 936 * 937 * @param email A String. 938 * @param name A String. 939 * @param charset The charset to encode the name with. 940 * @return An Email. 941 * @throws EmailException Indicates an invalid email address or charset. 942 * @since 1.1 943 */ 944 public Email addCc(final String email, final String name, final String charset) 945 throws EmailException 946 { 947 this.ccList.add(createInternetAddress(email, name, charset)); 948 return this; 949 } 950 951 /** 952 * Set a list of "CC" addresses. All elements in the specified 953 * <code>Collection</code> are expected to be of type 954 * <code>java.mail.internet.InternetAddress</code>. 955 * 956 * @param aCollection collection of <code>InternetAddress</code> objects. 957 * @return An Email. 958 * @throws EmailException Indicates an invalid email address. 959 * @see javax.mail.internet.InternetAddress 960 * @since 1.0 961 */ 962 public Email setCc(final Collection<InternetAddress> aCollection) throws EmailException 963 { 964 if (aCollection == null || aCollection.isEmpty()) 965 { 966 throw new EmailException("Address List provided was invalid"); 967 } 968 969 this.ccList = new ArrayList<InternetAddress>(aCollection); 970 return this; 971 } 972 973 /** 974 * Add a blind BCC recipient to the email. The email 975 * address will also be used as the personal name. 976 * The name will be encoded by the charset of {@link #setCharset(java.lang.String) setCharset()}. 977 * If it is not set, it will be encoded using 978 * the Java platform's default charset (UTF-16) if it contains 979 * non-ASCII characters; otherwise, it is used as is. 980 * 981 * @param email A String. 982 * @return An Email. 983 * @throws EmailException Indicates an invalid email address 984 * @since 1.0 985 */ 986 public Email addBcc(final String email) 987 throws EmailException 988 { 989 return this.addBcc(email, null); 990 } 991 992 /** 993 * Add an array of blind BCC recipients to the email. The email 994 * addresses will also be used as the personal name. 995 * The names will be encoded by the charset of 996 * {@link #setCharset(java.lang.String) setCharset()}. 997 * If it is not set, it will be encoded using 998 * the Java platform's default charset (UTF-16) if it contains 999 * non-ASCII characters; otherwise, it is used as is. 1000 * 1001 * @param emails A String array. 1002 * @return An Email. 1003 * @throws EmailException Indicates an invalid email address 1004 * @since 1.3 1005 */ 1006 public Email addBcc(final String... emails) 1007 throws EmailException 1008 { 1009 if (emails == null || emails.length == 0) 1010 { 1011 throw new EmailException("Address List provided was invalid"); 1012 } 1013 1014 for (final String email : emails) 1015 { 1016 addBcc(email, null); 1017 } 1018 1019 return this; 1020 } 1021 1022 /** 1023 * Add a blind BCC recipient to the email using the specified address and 1024 * the specified personal name. 1025 * The name will be encoded by the charset of {@link #setCharset(java.lang.String) setCharset()}. 1026 * If it is not set, it will be encoded using 1027 * the Java platform's default charset (UTF-16) if it contains 1028 * non-ASCII characters; otherwise, it is used as is. 1029 * 1030 * @param email A String. 1031 * @param name A String. 1032 * @return An Email. 1033 * @throws EmailException Indicates an invalid email address 1034 * @since 1.0 1035 */ 1036 public Email addBcc(final String email, final String name) 1037 throws EmailException 1038 { 1039 return addBcc(email, name, this.charset); 1040 } 1041 1042 /** 1043 * Add a blind BCC recipient to the email using the specified address, 1044 * personal name, and charset encoding for the name. 1045 * 1046 * @param email A String. 1047 * @param name A String. 1048 * @param charset The charset to encode the name with. 1049 * @return An Email. 1050 * @throws EmailException Indicates an invalid email address 1051 * @since 1.1 1052 */ 1053 public Email addBcc(final String email, final String name, final String charset) 1054 throws EmailException 1055 { 1056 this.bccList.add(createInternetAddress(email, name, charset)); 1057 return this; 1058 } 1059 1060 /** 1061 * Set a list of "BCC" addresses. All elements in the specified 1062 * <code>Collection</code> are expected to be of type 1063 * <code>java.mail.internet.InternetAddress</code>. 1064 * 1065 * @param aCollection collection of <code>InternetAddress</code> objects 1066 * @return An Email. 1067 * @throws EmailException Indicates an invalid email address 1068 * @see javax.mail.internet.InternetAddress 1069 * @since 1.0 1070 */ 1071 public Email setBcc(final Collection<InternetAddress> aCollection) throws EmailException 1072 { 1073 if (aCollection == null || aCollection.isEmpty()) 1074 { 1075 throw new EmailException("Address List provided was invalid"); 1076 } 1077 1078 this.bccList = new ArrayList<InternetAddress>(aCollection); 1079 return this; 1080 } 1081 1082 /** 1083 * Add a reply to address to the email. The email 1084 * address will also be used as the personal name. 1085 * The name will be encoded by the charset of {@link #setCharset(java.lang.String) setCharset()}. 1086 * If it is not set, it will be encoded using 1087 * the Java platform's default charset (UTF-16) if it contains 1088 * non-ASCII characters; otherwise, it is used as is. 1089 * 1090 * @param email A String. 1091 * @return An Email. 1092 * @throws EmailException Indicates an invalid email address 1093 * @since 1.0 1094 */ 1095 public Email addReplyTo(final String email) 1096 throws EmailException 1097 { 1098 return this.addReplyTo(email, null); 1099 } 1100 1101 /** 1102 * Add a reply to address to the email using the specified address and 1103 * the specified personal name. 1104 * The name will be encoded by the charset of {@link #setCharset(java.lang.String) setCharset()}. 1105 * If it is not set, it will be encoded using 1106 * the Java platform's default charset (UTF-16) if it contains 1107 * non-ASCII characters; otherwise, it is used as is. 1108 * 1109 * @param email A String. 1110 * @param name A String. 1111 * @return An Email. 1112 * @throws EmailException Indicates an invalid email address 1113 * @since 1.0 1114 */ 1115 public Email addReplyTo(final String email, final String name) 1116 throws EmailException 1117 { 1118 return addReplyTo(email, name, this.charset); 1119 } 1120 1121 /** 1122 * Add a reply to address to the email using the specified address, 1123 * personal name, and charset encoding for the name. 1124 * 1125 * @param email A String. 1126 * @param name A String. 1127 * @param charset The charset to encode the name with. 1128 * @return An Email. 1129 * @throws EmailException Indicates an invalid email address or charset. 1130 * @since 1.1 1131 */ 1132 public Email addReplyTo(final String email, final String name, final String charset) 1133 throws EmailException 1134 { 1135 this.replyList.add(createInternetAddress(email, name, charset)); 1136 return this; 1137 } 1138 1139 /** 1140 * Set a list of reply to addresses. All elements in the specified 1141 * <code>Collection</code> are expected to be of type 1142 * <code>java.mail.internet.InternetAddress</code>. 1143 * 1144 * @param aCollection collection of <code>InternetAddress</code> objects 1145 * @return An Email. 1146 * @throws EmailException Indicates an invalid email address 1147 * @see javax.mail.internet.InternetAddress 1148 * @since 1.1 1149 */ 1150 public Email setReplyTo(final Collection<InternetAddress> aCollection) throws EmailException 1151 { 1152 if (aCollection == null || aCollection.isEmpty()) 1153 { 1154 throw new EmailException("Address List provided was invalid"); 1155 } 1156 1157 this.replyList = new ArrayList<InternetAddress>(aCollection); 1158 return this; 1159 } 1160 1161 /** 1162 * Used to specify the mail headers. Example: 1163 * 1164 * X-Mailer: Sendmail, X-Priority: 1( highest ) 1165 * or 2( high ) 3( normal ) 4( low ) and 5( lowest ) 1166 * Disposition-Notification-To: user@domain.net 1167 * 1168 * @param map A Map. 1169 * @throws IllegalArgumentException if either of the provided header / value is null or empty 1170 * @since 1.0 1171 */ 1172 public void setHeaders(final Map<String, String> map) 1173 { 1174 this.headers.clear(); 1175 1176 for (final Map.Entry<String, String> entry : map.entrySet()) 1177 { 1178 addHeader(entry.getKey(), entry.getValue()); 1179 } 1180 } 1181 1182 /** 1183 * Adds a header ( name, value ) to the headers Map. 1184 * 1185 * @param name A String with the name. 1186 * @param value A String with the value. 1187 * @since 1.0 1188 * @throws IllegalArgumentException if either {@code name} or {@code value} is null or empty 1189 */ 1190 public void addHeader(final String name, final String value) 1191 { 1192 if (EmailUtils.isEmpty(name)) 1193 { 1194 throw new IllegalArgumentException("name can not be null or empty"); 1195 } 1196 if (EmailUtils.isEmpty(value)) 1197 { 1198 throw new IllegalArgumentException("value can not be null or empty"); 1199 } 1200 1201 this.headers.put(name, value); 1202 } 1203 1204 /** 1205 * Set the email subject. 1206 * 1207 * @param aSubject A String. 1208 * @return An Email. 1209 * @since 1.0 1210 */ 1211 public Email setSubject(final String aSubject) 1212 { 1213 this.subject = aSubject; 1214 return this; 1215 } 1216 1217 /** 1218 * Set the "bounce address" - the address to which undeliverable messages 1219 * will be returned. If this value is never set, then the message will be 1220 * sent to the address specified with the System property "mail.smtp.from", 1221 * or if that value is not set, then to the "from" address. 1222 * 1223 * @param email A String. 1224 * @return An Email. 1225 * @throws IllegalStateException when the mail session is already initialized 1226 * @since 1.0 1227 */ 1228 public Email setBounceAddress(final String email) 1229 { 1230 checkSessionAlreadyInitialized(); 1231 this.bounceAddress = email; 1232 return this; 1233 } 1234 1235 1236 /** 1237 * Define the content of the mail. It should be overridden by the 1238 * subclasses. 1239 * 1240 * @param msg A String. 1241 * @return An Email. 1242 * @throws EmailException generic exception. 1243 * @since 1.0 1244 */ 1245 public abstract Email setMsg(String msg) throws EmailException; 1246 1247 /** 1248 * Does the work of actually building the MimeMessage. Please note that 1249 * a user rarely calls this method directly and only if he/she is 1250 * interested in the sending the underlying MimeMessage without 1251 * commons-email. 1252 * 1253 * @throws IllegalStateException if the MimeMessage was already built 1254 * @throws EmailException if there was an error. 1255 * @since 1.0 1256 */ 1257 public void buildMimeMessage() throws EmailException 1258 { 1259 if (this.message != null) 1260 { 1261 // [EMAIL-95] we assume that an email is not reused therefore invoking 1262 // buildMimeMessage() more than once is illegal. 1263 throw new IllegalStateException("The MimeMessage is already built."); 1264 } 1265 1266 try 1267 { 1268 this.message = this.createMimeMessage(this.getMailSession()); 1269 1270 if (EmailUtils.isNotEmpty(this.subject)) 1271 { 1272 if (EmailUtils.isNotEmpty(this.charset)) 1273 { 1274 this.message.setSubject(this.subject, this.charset); 1275 } 1276 else 1277 { 1278 this.message.setSubject(this.subject); 1279 } 1280 } 1281 1282 // update content type (and encoding) 1283 this.updateContentType(this.contentType); 1284 1285 if (this.content != null) 1286 { 1287 if (EmailConstants.TEXT_PLAIN.equalsIgnoreCase(this.contentType) 1288 && this.content instanceof String) 1289 { 1290 // EMAIL-104: call explicitly setText to use default mime charset 1291 // (property "mail.mime.charset") in case none has been set 1292 this.message.setText(this.content.toString(), this.charset); 1293 } 1294 else 1295 { 1296 this.message.setContent(this.content, this.contentType); 1297 } 1298 } 1299 else if (this.emailBody != null) 1300 { 1301 if (this.contentType == null) 1302 { 1303 this.message.setContent(this.emailBody); 1304 } 1305 else 1306 { 1307 this.message.setContent(this.emailBody, this.contentType); 1308 } 1309 } 1310 else 1311 { 1312 this.message.setText(""); 1313 } 1314 1315 if (this.fromAddress != null) 1316 { 1317 this.message.setFrom(this.fromAddress); 1318 } 1319 else 1320 { 1321 if (session.getProperty(MAIL_SMTP_FROM) == null) 1322 { 1323 throw new EmailException("From address required"); 1324 } 1325 } 1326 1327 if (this.toList.size() + this.ccList.size() + this.bccList.size() == 0) 1328 { 1329 throw new EmailException("At least one receiver address required"); 1330 } 1331 1332 if (this.toList.size() > 0) 1333 { 1334 this.message.setRecipients( 1335 Message.RecipientType.TO, 1336 this.toInternetAddressArray(this.toList)); 1337 } 1338 1339 if (this.ccList.size() > 0) 1340 { 1341 this.message.setRecipients( 1342 Message.RecipientType.CC, 1343 this.toInternetAddressArray(this.ccList)); 1344 } 1345 1346 if (this.bccList.size() > 0) 1347 { 1348 this.message.setRecipients( 1349 Message.RecipientType.BCC, 1350 this.toInternetAddressArray(this.bccList)); 1351 } 1352 1353 if (this.replyList.size() > 0) 1354 { 1355 this.message.setReplyTo( 1356 this.toInternetAddressArray(this.replyList)); 1357 } 1358 1359 1360 if (this.headers.size() > 0) 1361 { 1362 for (final Map.Entry<String, String> entry : this.headers.entrySet()) 1363 { 1364 final String foldedValue = createFoldedHeaderValue(entry.getKey(), entry.getValue()); 1365 this.message.addHeader(entry.getKey(), foldedValue); 1366 } 1367 } 1368 1369 if (this.message.getSentDate() == null) 1370 { 1371 this.message.setSentDate(getSentDate()); 1372 } 1373 1374 if (this.popBeforeSmtp) 1375 { 1376 final Store store = session.getStore("pop3"); 1377 store.connect(this.popHost, this.popUsername, this.popPassword); 1378 } 1379 } 1380 catch (final MessagingException me) 1381 { 1382 throw new EmailException(me); 1383 } 1384 } 1385 1386 /** 1387 * Sends the previously created MimeMessage to the SMTP server. 1388 * 1389 * @return the message id of the underlying MimeMessage 1390 * @throws IllegalArgumentException if the MimeMessage has not been created 1391 * @throws EmailException the sending failed 1392 */ 1393 public String sendMimeMessage() 1394 throws EmailException 1395 { 1396 EmailUtils.notNull(this.message, "MimeMessage has not been created yet"); 1397 1398 try 1399 { 1400 Transport.send(this.message); 1401 return this.message.getMessageID(); 1402 } 1403 catch (final Throwable t) 1404 { 1405 final String msg = "Sending the email to the following server failed : " 1406 + this.getHostName() 1407 + ":" 1408 + this.getSmtpPort(); 1409 1410 throw new EmailException(msg, t); 1411 } 1412 } 1413 1414 /** 1415 * Returns the internal MimeMessage. Please not that the 1416 * MimeMessage is build by the buildMimeMessage() method. 1417 * 1418 * @return the MimeMessage 1419 */ 1420 public MimeMessage getMimeMessage() 1421 { 1422 return this.message; 1423 } 1424 1425 /** 1426 * Sends the email. Internally we build a MimeMessage 1427 * which is afterwards sent to the SMTP server. 1428 * 1429 * @return the message id of the underlying MimeMessage 1430 * @throws IllegalStateException if the MimeMessage was already built, ie {@link #buildMimeMessage()} 1431 * was already called 1432 * @throws EmailException the sending failed 1433 */ 1434 public String send() throws EmailException 1435 { 1436 this.buildMimeMessage(); 1437 return this.sendMimeMessage(); 1438 } 1439 1440 /** 1441 * Sets the sent date for the email. The sent date will default to the 1442 * current date if not explicitly set. 1443 * 1444 * @param date Date to use as the sent date on the email 1445 * @since 1.0 1446 */ 1447 public void setSentDate(final Date date) 1448 { 1449 if (date != null) 1450 { 1451 // create a separate instance to keep findbugs happy 1452 this.sentDate = new Date(date.getTime()); 1453 } 1454 } 1455 1456 /** 1457 * Gets the sent date for the email. 1458 * 1459 * @return date to be used as the sent date for the email 1460 * @since 1.0 1461 */ 1462 public Date getSentDate() 1463 { 1464 if (this.sentDate == null) 1465 { 1466 return new Date(); 1467 } 1468 return new Date(this.sentDate.getTime()); 1469 } 1470 1471 /** 1472 * Gets the subject of the email. 1473 * 1474 * @return email subject 1475 */ 1476 public String getSubject() 1477 { 1478 return this.subject; 1479 } 1480 1481 /** 1482 * Gets the sender of the email. 1483 * 1484 * @return from address 1485 */ 1486 public InternetAddress getFromAddress() 1487 { 1488 return this.fromAddress; 1489 } 1490 1491 /** 1492 * Gets the host name of the SMTP server, 1493 * 1494 * @return host name 1495 */ 1496 public String getHostName() 1497 { 1498 if (this.session != null) 1499 { 1500 return this.session.getProperty(MAIL_HOST); 1501 } 1502 else if (EmailUtils.isNotEmpty(this.hostName)) 1503 { 1504 return this.hostName; 1505 } 1506 return null; 1507 } 1508 1509 /** 1510 * Gets the listening port of the SMTP server. 1511 * 1512 * @return smtp port 1513 */ 1514 public String getSmtpPort() 1515 { 1516 if (this.session != null) 1517 { 1518 return this.session.getProperty(MAIL_PORT); 1519 } 1520 else if (EmailUtils.isNotEmpty(this.smtpPort)) 1521 { 1522 return this.smtpPort; 1523 } 1524 return null; 1525 } 1526 1527 /** 1528 * Gets whether the client is configured to require STARTTLS. 1529 * 1530 * @return true if using STARTTLS for authentication, false otherwise 1531 * @since 1.3 1532 */ 1533 public boolean isStartTLSRequired() 1534 { 1535 return this.startTlsRequired; 1536 } 1537 1538 /** 1539 * Gets whether the client is configured to try to enable STARTTLS. 1540 * 1541 * @return true if using STARTTLS for authentication, false otherwise 1542 * @since 1.3 1543 */ 1544 public boolean isStartTLSEnabled() 1545 { 1546 return this.startTlsEnabled || tls; 1547 } 1548 1549 /** 1550 * Gets whether the client is configured to try to enable STARTTLS. 1551 * See EMAIL-105 for reason of deprecation. 1552 * 1553 * @deprecated since 1.3, use isStartTLSEnabled() instead 1554 * @return true if using STARTTLS for authentication, false otherwise 1555 * @since 1.1 1556 */ 1557 @Deprecated 1558 public boolean isTLS() 1559 { 1560 return isStartTLSEnabled(); 1561 } 1562 1563 /** 1564 * Utility to copy List of known InternetAddress objects into an 1565 * array. 1566 * 1567 * @param list A List. 1568 * @return An InternetAddress[]. 1569 * @since 1.0 1570 */ 1571 protected InternetAddress[] toInternetAddressArray(final List<InternetAddress> list) 1572 { 1573 return list.toArray(new InternetAddress[list.size()]); 1574 } 1575 1576 /** 1577 * Set details regarding "pop3 before smtp" authentication. 1578 * 1579 * @param newPopBeforeSmtp Whether or not to log into pop3 server before sending mail. 1580 * @param newPopHost The pop3 host to use. 1581 * @param newPopUsername The pop3 username. 1582 * @param newPopPassword The pop3 password. 1583 * @since 1.0 1584 */ 1585 public void setPopBeforeSmtp( 1586 final boolean newPopBeforeSmtp, 1587 final String newPopHost, 1588 final String newPopUsername, 1589 final String newPopPassword) 1590 { 1591 this.popBeforeSmtp = newPopBeforeSmtp; 1592 this.popHost = newPopHost; 1593 this.popUsername = newPopUsername; 1594 this.popPassword = newPopPassword; 1595 } 1596 1597 /** 1598 * Returns whether SSL/TLS encryption for the transport is currently enabled (SMTPS/POPS). 1599 * See EMAIL-105 for reason of deprecation. 1600 * 1601 * @deprecated since 1.3, use isSSLOnConnect() instead 1602 * @return true if SSL enabled for the transport 1603 */ 1604 @Deprecated 1605 public boolean isSSL() 1606 { 1607 return isSSLOnConnect(); 1608 } 1609 1610 /** 1611 * Returns whether SSL/TLS encryption for the transport is currently enabled (SMTPS/POPS). 1612 * 1613 * @return true if SSL enabled for the transport 1614 * @since 1.3 1615 */ 1616 public boolean isSSLOnConnect() 1617 { 1618 return sslOnConnect || ssl; 1619 } 1620 1621 /** 1622 * Sets whether SSL/TLS encryption should be enabled for the SMTP transport upon connection (SMTPS/POPS). 1623 * See EMAIL-105 for reason of deprecation. 1624 * 1625 * @deprecated since 1.3, use setSSLOnConnect() instead 1626 * @param ssl whether to enable the SSL transport 1627 */ 1628 @Deprecated 1629 public void setSSL(final boolean ssl) 1630 { 1631 setSSLOnConnect(ssl); 1632 } 1633 1634 /** 1635 * Sets whether SSL/TLS encryption should be enabled for the SMTP transport upon connection (SMTPS/POPS). 1636 * 1637 * @param ssl whether to enable the SSL transport 1638 * @return An Email. 1639 * @since 1.3 1640 */ 1641 public Email setSSLOnConnect(final boolean ssl) 1642 { 1643 checkSessionAlreadyInitialized(); 1644 this.sslOnConnect = ssl; 1645 this.ssl = ssl; 1646 return this; 1647 } 1648 1649 /** 1650 * Is the server identity checked as specified by RFC 2595 1651 * 1652 * @return true if the server identity is checked 1653 * @since 1.3 1654 */ 1655 public boolean isSSLCheckServerIdentity() 1656 { 1657 return sslCheckServerIdentity; 1658 } 1659 1660 /** 1661 * Sets whether the server identity is checked as specified by RFC 2595 1662 * 1663 * @param sslCheckServerIdentity whether to enable server identity check 1664 * @return An Email. 1665 * @since 1.3 1666 */ 1667 public Email setSSLCheckServerIdentity(final boolean sslCheckServerIdentity) 1668 { 1669 checkSessionAlreadyInitialized(); 1670 this.sslCheckServerIdentity = sslCheckServerIdentity; 1671 return this; 1672 } 1673 1674 /** 1675 * Returns the current SSL port used by the SMTP transport. 1676 * 1677 * @return the current SSL port used by the SMTP transport 1678 */ 1679 public String getSslSmtpPort() 1680 { 1681 if (this.session != null) 1682 { 1683 return this.session.getProperty(MAIL_SMTP_SOCKET_FACTORY_PORT); 1684 } 1685 else if (EmailUtils.isNotEmpty(this.sslSmtpPort)) 1686 { 1687 return this.sslSmtpPort; 1688 } 1689 return null; 1690 } 1691 1692 /** 1693 * Sets the SSL port to use for the SMTP transport. Defaults to the standard 1694 * port, 465. 1695 * 1696 * @param sslSmtpPort the SSL port to use for the SMTP transport 1697 */ 1698 public void setSslSmtpPort(final String sslSmtpPort) 1699 { 1700 checkSessionAlreadyInitialized(); 1701 this.sslSmtpPort = sslSmtpPort; 1702 } 1703 1704 /** 1705 * If partial sending of email enabled. 1706 * 1707 * @return true if sending partial email is enabled 1708 * @since 1.3.2 1709 */ 1710 public boolean isSendPartial() 1711 { 1712 return sendPartial; 1713 } 1714 1715 /** 1716 * Sets whether the email is partially send in case of invalid addresses. 1717 * <p> 1718 * In case the mail server rejects an address as invalid, the call to {@link #send()} 1719 * may throw a {@link javax.mail.SendFailedException}, even if partial send mode is enabled (emails 1720 * to valid addresses will be transmitted). In case the email server does not reject 1721 * invalid addresses immediately, but return a bounce message, no exception will be thrown 1722 * by the {@link #send()} method. 1723 * 1724 * @param sendPartial whether to enable partial send mode 1725 * @return An Email. 1726 * @since 1.3.2 1727 */ 1728 public Email setSendPartial(final boolean sendPartial) 1729 { 1730 checkSessionAlreadyInitialized(); 1731 this.sendPartial = sendPartial; 1732 return this; 1733 } 1734 1735 /** 1736 * Get the list of "To" addresses. 1737 * 1738 * @return List addresses 1739 */ 1740 public List<InternetAddress> getToAddresses() 1741 { 1742 return this.toList; 1743 } 1744 1745 /** 1746 * Get the list of "CC" addresses. 1747 * 1748 * @return List addresses 1749 */ 1750 public List<InternetAddress> getCcAddresses() 1751 { 1752 return this.ccList; 1753 } 1754 1755 /** 1756 * Get the list of "Bcc" addresses. 1757 * 1758 * @return List addresses 1759 */ 1760 public List<InternetAddress> getBccAddresses() 1761 { 1762 return this.bccList; 1763 } 1764 1765 /** 1766 * Get the list of "Reply-To" addresses. 1767 * 1768 * @return List addresses 1769 */ 1770 public List<InternetAddress> getReplyToAddresses() 1771 { 1772 return this.replyList; 1773 } 1774 1775 /** 1776 * Get the socket connection timeout value in milliseconds. 1777 * 1778 * @return the timeout in milliseconds. 1779 * @since 1.2 1780 */ 1781 public int getSocketConnectionTimeout() 1782 { 1783 return this.socketConnectionTimeout; 1784 } 1785 1786 /** 1787 * Set the socket connection timeout value in milliseconds. 1788 * Default is a 60 second timeout. 1789 * 1790 * @param socketConnectionTimeout the connection timeout 1791 * @since 1.2 1792 */ 1793 public void setSocketConnectionTimeout(final int socketConnectionTimeout) 1794 { 1795 checkSessionAlreadyInitialized(); 1796 this.socketConnectionTimeout = socketConnectionTimeout; 1797 } 1798 1799 /** 1800 * Get the socket I/O timeout value in milliseconds. 1801 * 1802 * @return the socket I/O timeout 1803 * @since 1.2 1804 */ 1805 public int getSocketTimeout() 1806 { 1807 return this.socketTimeout; 1808 } 1809 1810 /** 1811 * Set the socket I/O timeout value in milliseconds. 1812 * Default is 60 second timeout. 1813 * 1814 * @param socketTimeout the socket I/O timeout 1815 * @since 1.2 1816 */ 1817 public void setSocketTimeout(final int socketTimeout) 1818 { 1819 checkSessionAlreadyInitialized(); 1820 this.socketTimeout = socketTimeout; 1821 } 1822 1823 /** 1824 * Factory method to create a customized MimeMessage which can be 1825 * implemented by a derived class, e.g. to set the message id. 1826 * 1827 * @param aSession mail session to be used 1828 * @return the newly created message 1829 */ 1830 protected MimeMessage createMimeMessage(final Session aSession) 1831 { 1832 return new MimeMessage(aSession); 1833 } 1834 1835 /** 1836 * Create a folded header value containing 76 character chunks. 1837 * 1838 * @param name the name of the header 1839 * @param value the value of the header 1840 * @return the folded header value 1841 * @throws IllegalArgumentException if either the name or value is null or empty 1842 */ 1843 private String createFoldedHeaderValue(final String name, final Object value) 1844 { 1845 String result; 1846 1847 if (EmailUtils.isEmpty(name)) 1848 { 1849 throw new IllegalArgumentException("name can not be null or empty"); 1850 } 1851 if (value == null || EmailUtils.isEmpty(value.toString())) 1852 { 1853 throw new IllegalArgumentException("value can not be null or empty"); 1854 } 1855 1856 try 1857 { 1858 result = MimeUtility.fold(name.length() + 2, MimeUtility.encodeText(value.toString(), this.charset, null)); 1859 } 1860 catch (final UnsupportedEncodingException e) 1861 { 1862 result = value.toString(); 1863 } 1864 1865 return result; 1866 } 1867 1868 /** 1869 * Creates a InternetAddress. 1870 * 1871 * @param email An email address. 1872 * @param name A name. 1873 * @param charsetName The name of the charset to encode the name with. 1874 * @return An internet address. 1875 * @throws EmailException Thrown when the supplied address, name or charset were invalid. 1876 */ 1877 private InternetAddress createInternetAddress(final String email, final String name, final String charsetName) 1878 throws EmailException 1879 { 1880 InternetAddress address = null; 1881 1882 try 1883 { 1884 address = new InternetAddress(email); 1885 1886 // check name input 1887 if (EmailUtils.isNotEmpty(name)) 1888 { 1889 // check charset input. 1890 if (EmailUtils.isEmpty(charsetName)) 1891 { 1892 address.setPersonal(name); 1893 } 1894 else 1895 { 1896 // canonicalize the charset name and make sure 1897 // the current platform supports it. 1898 final Charset set = Charset.forName(charsetName); 1899 address.setPersonal(name, set.name()); 1900 } 1901 } 1902 1903 // run sanity check on new InternetAddress object; if this fails 1904 // it will throw AddressException. 1905 address.validate(); 1906 } 1907 catch (final AddressException e) 1908 { 1909 throw new EmailException(e); 1910 } 1911 catch (final UnsupportedEncodingException e) 1912 { 1913 throw new EmailException(e); 1914 } 1915 return address; 1916 } 1917 1918 /** 1919 * When a mail session is already initialized setting the 1920 * session properties has no effect. In order to flag the 1921 * problem throw an IllegalStateException. 1922 * 1923 * @throws IllegalStateException when the mail session is already initialized 1924 */ 1925 private void checkSessionAlreadyInitialized() 1926 { 1927 if (this.session != null) 1928 { 1929 throw new IllegalStateException("The mail session is already initialized"); 1930 } 1931 } 1932}