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