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