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