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