Email.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *     http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.apache.commons.mail2.javax;

  18. import java.io.UnsupportedEncodingException;
  19. import java.nio.charset.Charset;
  20. import java.time.Duration;
  21. import java.util.ArrayList;
  22. import java.util.Collection;
  23. import java.util.Date;
  24. import java.util.HashMap;
  25. import java.util.List;
  26. import java.util.Map;
  27. import java.util.Objects;
  28. import java.util.Properties;

  29. import javax.mail.Authenticator;
  30. import javax.mail.Message;
  31. import javax.mail.MessagingException;
  32. import javax.mail.Session;
  33. import javax.mail.Store;
  34. import javax.mail.Transport;
  35. import javax.mail.internet.AddressException;
  36. import javax.mail.internet.InternetAddress;
  37. import javax.mail.internet.MimeMessage;
  38. import javax.mail.internet.MimeMultipart;
  39. import javax.mail.internet.MimeUtility;
  40. import javax.naming.Context;
  41. import javax.naming.InitialContext;
  42. import javax.naming.NamingException;

  43. import org.apache.commons.mail2.core.EmailConstants;
  44. import org.apache.commons.mail2.core.EmailException;
  45. import org.apache.commons.mail2.core.EmailUtils;
  46. import org.apache.commons.mail2.javax.util.IDNEmailAddressConverter;

  47. /**
  48.  * The abstract class for all email messages. This class sets the sender's email, name, receiver's email, name, subject, and send date.
  49.  * <p>
  50.  * Subclasses are responsible for setting the message body.
  51.  * </p>
  52.  *
  53.  * @since 1.0
  54.  */
  55. public abstract class Email {

  56.     /**
  57.      * Empty array.
  58.      */
  59.     private static final InternetAddress[] EMPTY_INTERNET_ADDRESS_ARRAY = {};

  60.     /**
  61.      * The email message to send.
  62.      */
  63.     private MimeMessage message;

  64.     /**
  65.      * The charset to use for this message.
  66.      */
  67.     private String charset;

  68.     /**
  69.      * The Address of the sending party, mandatory.
  70.      */
  71.     private InternetAddress fromAddress;

  72.     /**
  73.      * The Subject.
  74.      */
  75.     private String subject;

  76.     /**
  77.      * An attachment.
  78.      */
  79.     private MimeMultipart emailBody;

  80.     /**
  81.      * The content.
  82.      */
  83.     private Object content;

  84.     /**
  85.      * The content type.
  86.      */
  87.     private String contentType;

  88.     /**
  89.      * Set session debugging on or off.
  90.      */
  91.     private boolean debug;

  92.     /**
  93.      * Sent date.
  94.      */
  95.     private Date sentDate;

  96.     /**
  97.      * Instance of an {@code Authenticator} object that will be used when authentication is requested from the mail server.
  98.      */
  99.     private Authenticator authenticator;

  100.     /**
  101.      * The hostname of the mail server with which to connect. If null will try to get property from system.properties. If still null, quit.
  102.      */
  103.     private String hostName;

  104.     /**
  105.      * The port number of the mail server to connect to. Defaults to the standard port ( 25 ).
  106.      */
  107.     private String smtpPort = "25";

  108.     /**
  109.      * The port number of the SSL enabled SMTP server; defaults to the standard port, 465.
  110.      */
  111.     private String sslSmtpPort = "465";

  112.     /**
  113.      * List of "to" email addresses.
  114.      */
  115.     private List<InternetAddress> toList = new ArrayList<>();

  116.     /**
  117.      * List of "cc" email addresses.
  118.      */
  119.     private List<InternetAddress> ccList = new ArrayList<>();

  120.     /**
  121.      * List of "bcc" email addresses.
  122.      */
  123.     private List<InternetAddress> bccList = new ArrayList<>();

  124.     /**
  125.      * List of "replyTo" email addresses.
  126.      */
  127.     private List<InternetAddress> replyList = new ArrayList<>();

  128.     /**
  129.      * 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
  130.      * type {@code String} rather than {@code InternetAddress}.
  131.      */
  132.     private String bounceAddress;

  133.     /**
  134.      * Used to specify the mail headers. Example:
  135.      *
  136.      * X-Mailer: Sendmail, X-Priority: 1( highest ) or 2( high ) 3( normal ) 4( low ) and 5( lowest ) Disposition-Notification-To: user@domain.net
  137.      */
  138.     private final Map<String, String> headers = new HashMap<>();

  139.     /**
  140.      * Whether to use POP3 before SMTP, and if so the settings.
  141.      */
  142.     private boolean popBeforeSmtp;

  143.     /**
  144.      * The host name of the POP3 server.
  145.      */
  146.     private String popHost;

  147.     /**
  148.      * The user name to log into the POP3 server.
  149.      */
  150.     private String popUsername;

  151.     /**
  152.      * The password to log into the POP3 server.
  153.      */
  154.     private String popPassword;

  155.     /**
  156.      * Does server require TLS encryption for authentication?
  157.      */
  158.     private boolean tls;

  159.     /**
  160.      * Does the current transport use SSL/TLS encryption upon connection?
  161.      */
  162.     private boolean ssl;

  163.     /**
  164.      * Socket I/O timeout value in milliseconds.
  165.      */
  166.     private int socketTimeout = Math.toIntExact(EmailConstants.SOCKET_TIMEOUT.toMillis());

  167.     /**
  168.      * Socket connection timeout value in milliseconds.
  169.      */
  170.     private int socketConnectionTimeout = Math.toIntExact(EmailConstants.SOCKET_TIMEOUT.toMillis());

  171.     /**
  172.      * 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
  173.      * login commands. Note that an appropriate trust store must configured so that the client will trust the server's certificate. Defaults to false.
  174.      */
  175.     private boolean startTlsEnabled;

  176.     /**
  177.      * 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
  178.      * fail. Defaults to false.
  179.      */
  180.     private boolean startTlsRequired;

  181.     /**
  182.      * Does the current transport use SSL/TLS encryption upon connection?
  183.      */
  184.     private boolean sslOnConnect;

  185.     /**
  186.      * 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
  187.      * to prevent man-in-the-middle attacks. Defaults to false.
  188.      */
  189.     private boolean sslCheckServerIdentity;

  190.     /**
  191.      * If set to true, and a message has some valid and some invalid addresses, send the message anyway, reporting the partial failure with a
  192.      * 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
  193.      * to false.
  194.      */
  195.     private boolean sendPartial;

  196.     /**
  197.      * The Session to mail with.
  198.      */
  199.     private Session session;

  200.     /**
  201.      * Constructs a new instance.
  202.      */
  203.     public Email() {
  204.         // empty
  205.     }

  206.     /**
  207.      * 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
  208.      * {@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;
  209.      * otherwise, it is used as is.
  210.      *
  211.      * @param email A String.
  212.      * @return An Email.
  213.      * @throws EmailException Indicates an invalid email address
  214.      * @since 1.0
  215.      */
  216.     public Email addBcc(final String email) throws EmailException {
  217.         return addBcc(email, null);
  218.     }

  219.     /**
  220.      * 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
  221.      * 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
  222.      * characters; otherwise, it is used as is.
  223.      *
  224.      * @param emails A String array.
  225.      * @return An Email.
  226.      * @throws EmailException Indicates an invalid email address
  227.      * @since 1.3
  228.      */
  229.     public Email addBcc(final String... emails) throws EmailException {
  230.         EmailException.checkNonEmpty(emails, () -> "BCC list invalid.");
  231.         for (final String email : emails) {
  232.             addBcc(email, null);
  233.         }
  234.         return this;
  235.     }

  236.     /**
  237.      * 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
  238.      * {@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;
  239.      * otherwise, it is used as is.
  240.      *
  241.      * @param email A String.
  242.      * @param name  A String.
  243.      * @return An Email.
  244.      * @throws EmailException Indicates an invalid email address
  245.      * @since 1.0
  246.      */
  247.     public Email addBcc(final String email, final String name) throws EmailException {
  248.         return addBcc(email, name, charset);
  249.     }

  250.     /**
  251.      * Adds a blind BCC recipient to the email using the specified address, personal name, and charset encoding for the name.
  252.      *
  253.      * @param email   A String.
  254.      * @param name    A String.
  255.      * @param charset The charset to encode the name with.
  256.      * @return An Email.
  257.      * @throws EmailException Indicates an invalid email address
  258.      * @since 1.1
  259.      */
  260.     public Email addBcc(final String email, final String name, final String charset) throws EmailException {
  261.         bccList.add(createInternetAddress(email, name, charset));
  262.         return this;
  263.     }

  264.     /**
  265.      * 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
  266.      * {@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;
  267.      * otherwise, it is used as is.
  268.      *
  269.      * @param email A String.
  270.      * @return An Email.
  271.      * @throws EmailException Indicates an invalid email address.
  272.      * @since 1.0
  273.      */
  274.     public Email addCc(final String email) throws EmailException {
  275.         return addCc(email, null);
  276.     }

  277.     /**
  278.      * 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
  279.      * {@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;
  280.      * otherwise, it is used as is.
  281.      *
  282.      * @param emails A String array.
  283.      * @return An Email.
  284.      * @throws EmailException Indicates an invalid email address.
  285.      * @since 1.3
  286.      */
  287.     public Email addCc(final String... emails) throws EmailException {
  288.         EmailException.checkNonEmpty(emails, () -> "CC list invalid.");
  289.         for (final String email : emails) {
  290.             addCc(email, null);
  291.         }
  292.         return this;
  293.     }

  294.     /**
  295.      * 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
  296.      * {@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;
  297.      * otherwise, it is used as is.
  298.      *
  299.      * @param email A String.
  300.      * @param name  A String.
  301.      * @return An Email.
  302.      * @throws EmailException Indicates an invalid email address.
  303.      * @since 1.0
  304.      */
  305.     public Email addCc(final String email, final String name) throws EmailException {
  306.         return addCc(email, name, charset);
  307.     }

  308.     /**
  309.      * Adds a recipient CC to the email using the specified address, personal name, and charset encoding for the name.
  310.      *
  311.      * @param email   A String.
  312.      * @param name    A String.
  313.      * @param charset The charset to encode the name with.
  314.      * @return An Email.
  315.      * @throws EmailException Indicates an invalid email address or charset.
  316.      * @since 1.1
  317.      */
  318.     public Email addCc(final String email, final String name, final String charset) throws EmailException {
  319.         ccList.add(createInternetAddress(email, name, charset));
  320.         return this;
  321.     }

  322.     /**
  323.      * Adds a header ( name, value ) to the headers Map.
  324.      *
  325.      * @param name  A String with the name.
  326.      * @param value A String with the value.
  327.      * @since 1.0
  328.      * @throws IllegalArgumentException if either {@code name} or {@code value} is null or empty
  329.      */
  330.     public void addHeader(final String name, final String value) {
  331.         if (EmailUtils.isEmpty(name)) {
  332.             throw new IllegalArgumentException("name can not be null or empty");
  333.         }
  334.         if (EmailUtils.isEmpty(value)) {
  335.             throw new IllegalArgumentException("value can not be null or empty");
  336.         }
  337.         headers.put(name, value);
  338.     }

  339.     /**
  340.      * 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
  341.      * {@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;
  342.      * otherwise, it is used as is.
  343.      *
  344.      * @param email A String.
  345.      * @return An Email.
  346.      * @throws EmailException Indicates an invalid email address
  347.      * @since 1.0
  348.      */
  349.     public Email addReplyTo(final String email) throws EmailException {
  350.         return addReplyTo(email, null);
  351.     }

  352.     /**
  353.      * 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
  354.      * {@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;
  355.      * otherwise, it is used as is.
  356.      *
  357.      * @param email A String.
  358.      * @param name  A String.
  359.      * @return An Email.
  360.      * @throws EmailException Indicates an invalid email address
  361.      * @since 1.0
  362.      */
  363.     public Email addReplyTo(final String email, final String name) throws EmailException {
  364.         return addReplyTo(email, name, charset);
  365.     }

  366.     /**
  367.      * Adds a reply to address to the email using the specified address, personal name, and charset encoding for the name.
  368.      *
  369.      * @param email   A String.
  370.      * @param name    A String.
  371.      * @param charset The charset to encode the name with.
  372.      * @return An Email.
  373.      * @throws EmailException Indicates an invalid email address or charset.
  374.      * @since 1.1
  375.      */
  376.     public Email addReplyTo(final String email, final String name, final String charset) throws EmailException {
  377.         replyList.add(createInternetAddress(email, name, charset));
  378.         return this;
  379.     }

  380.     /**
  381.      * 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
  382.      * {@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;
  383.      * otherwise, it is used as is.
  384.      *
  385.      * @param email A String.
  386.      * @return An Email.
  387.      * @throws EmailException Indicates an invalid email address.
  388.      * @since 1.0
  389.      */
  390.     public Email addTo(final String email) throws EmailException {
  391.         return addTo(email, null);
  392.     }

  393.     /**
  394.      * 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
  395.      * {@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;
  396.      * otherwise, it is used as is.
  397.      *
  398.      * @param emails A String array.
  399.      * @return An Email.
  400.      * @throws EmailException Indicates an invalid email address.
  401.      * @since 1.3
  402.      */
  403.     public Email addTo(final String... emails) throws EmailException {
  404.         EmailException.checkNonEmpty(emails, () -> "To list invalid.");
  405.         for (final String email : emails) {
  406.             addTo(email, null);
  407.         }
  408.         return this;
  409.     }

  410.     /**
  411.      * 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
  412.      * {@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;
  413.      * otherwise, it is used as is.
  414.      *
  415.      * @param email A String.
  416.      * @param name  A String.
  417.      * @return An Email.
  418.      * @throws EmailException Indicates an invalid email address.
  419.      * @since 1.0
  420.      */
  421.     public Email addTo(final String email, final String name) throws EmailException {
  422.         return addTo(email, name, charset);
  423.     }

  424.     /**
  425.      * Adds a recipient TO to the email using the specified address, personal name, and charset encoding for the name.
  426.      *
  427.      * @param email   A String.
  428.      * @param name    A String.
  429.      * @param charset The charset to encode the name with.
  430.      * @return An Email.
  431.      * @throws EmailException Indicates an invalid email address or charset.
  432.      * @since 1.1
  433.      */
  434.     public Email addTo(final String email, final String name, final String charset) throws EmailException {
  435.         toList.add(createInternetAddress(email, name, charset));
  436.         return this;
  437.     }

  438.     /**
  439.      * 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
  440.      * MimeMessage without commons-email.
  441.      *
  442.      * @throws IllegalStateException if the MimeMessage was already built
  443.      * @throws EmailException        if there was an error.
  444.      * @since 1.0
  445.      */
  446.     public void buildMimeMessage() throws EmailException {
  447.         if (message != null) {
  448.             // [EMAIL-95] we assume that an email is not reused therefore invoking
  449.             // buildMimeMessage() more than once is illegal.
  450.             throw new IllegalStateException("The MimeMessage is already built.");
  451.         }

  452.         try {
  453.             message = createMimeMessage(getMailSession());

  454.             if (EmailUtils.isNotEmpty(subject)) {
  455.                 if (EmailUtils.isNotEmpty(charset)) {
  456.                     message.setSubject(subject, charset);
  457.                 } else {
  458.                     message.setSubject(subject);
  459.                 }
  460.             }

  461.             // update content type (and encoding)
  462.             updateContentType(contentType);

  463.             if (content != null) {
  464.                 if (EmailConstants.TEXT_PLAIN.equalsIgnoreCase(contentType) && content instanceof String) {
  465.                     // EMAIL-104: call explicitly setText to use default mime charset
  466.                     // (property "mail.mime.charset") in case none has been set
  467.                     message.setText(content.toString(), charset);
  468.                 } else {
  469.                     message.setContent(content, contentType);
  470.                 }
  471.             } else if (emailBody != null) {
  472.                 if (contentType == null) {
  473.                     message.setContent(emailBody);
  474.                 } else {
  475.                     message.setContent(emailBody, contentType);
  476.                 }
  477.             } else {
  478.                 message.setText("");
  479.             }

  480.             if (fromAddress != null) {
  481.                 message.setFrom(fromAddress);
  482.             } else if (session.getProperty(EmailConstants.MAIL_SMTP_FROM) == null && session.getProperty(EmailConstants.MAIL_FROM) == null) {
  483.                 throw new EmailException("From address required");
  484.             }

  485.             if (toList.size() + ccList.size() + bccList.size() == 0) {
  486.                 throw new EmailException("At least one receiver address required");
  487.             }

  488.             if (!EmailUtils.isEmpty(toList)) {
  489.                 message.setRecipients(Message.RecipientType.TO, toInternetAddressArray(toList));
  490.             }

  491.             if (!EmailUtils.isEmpty(ccList)) {
  492.                 message.setRecipients(Message.RecipientType.CC, toInternetAddressArray(ccList));
  493.             }

  494.             if (!EmailUtils.isEmpty(bccList)) {
  495.                 message.setRecipients(Message.RecipientType.BCC, toInternetAddressArray(bccList));
  496.             }

  497.             if (!EmailUtils.isEmpty(replyList)) {
  498.                 message.setReplyTo(toInternetAddressArray(replyList));
  499.             }

  500.             if (!EmailUtils.isEmpty(headers)) {
  501.                 for (final Map.Entry<String, String> entry : headers.entrySet()) {
  502.                     final String foldedValue = createFoldedHeaderValue(entry.getKey(), entry.getValue());
  503.                     message.addHeader(entry.getKey(), foldedValue);
  504.                 }
  505.             }

  506.             if (message.getSentDate() == null) {
  507.                 message.setSentDate(getSentDate());
  508.             }

  509.             if (popBeforeSmtp) {
  510.                 // TODO Why is this not a Store leak? When to close?
  511.                 final Store store = session.getStore("pop3");
  512.                 store.connect(popHost, popUsername, popPassword);
  513.             }
  514.         } catch (final MessagingException e) {
  515.             throw new EmailException(e);
  516.         }
  517.     }

  518.     /**
  519.      * When a mail session is already initialized setting the session properties has no effect. In order to flag the problem throw an IllegalStateException.
  520.      *
  521.      * @throws IllegalStateException when the mail session is already initialized
  522.      */
  523.     private void checkSessionAlreadyInitialized() {
  524.         if (session != null) {
  525.             throw new IllegalStateException("The mail session is already initialized");
  526.         }
  527.     }

  528.     /**
  529.      * Creates a folded header value containing 76 character chunks.
  530.      *
  531.      * @param name  the name of the header
  532.      * @param value the value of the header
  533.      * @return the folded header value
  534.      * @throws IllegalArgumentException if either the name or value is null or empty
  535.      */
  536.     private String createFoldedHeaderValue(final String name, final String value) {
  537.         if (EmailUtils.isEmpty(name)) {
  538.             throw new IllegalArgumentException("name can not be null or empty");
  539.         }
  540.         if (EmailUtils.isEmpty(value)) {
  541.             throw new IllegalArgumentException("value can not be null or empty");
  542.         }
  543.         try {
  544.             return MimeUtility.fold(name.length() + 2, MimeUtility.encodeText(value, charset, null));
  545.         } catch (final UnsupportedEncodingException e) {
  546.             return value;
  547.         }
  548.     }

  549.     /**
  550.      * Creates an InternetAddress.
  551.      *
  552.      * @param email       An email address.
  553.      * @param name        A name.
  554.      * @param charsetName The name of the charset to encode the name with.
  555.      * @return An internet address.
  556.      * @throws EmailException Thrown when the supplied address, name or charset were invalid.
  557.      */
  558.     private InternetAddress createInternetAddress(final String email, final String name, final String charsetName) throws EmailException {
  559.         try {
  560.             final InternetAddress address = new InternetAddress(new IDNEmailAddressConverter().toASCII(email));
  561.             // check name input
  562.             if (EmailUtils.isNotEmpty(name)) {
  563.                 // check charset input.
  564.                 if (EmailUtils.isEmpty(charsetName)) {
  565.                     address.setPersonal(name);
  566.                 } else {
  567.                     // canonicalize the charset name and make sure
  568.                     // the current platform supports it.
  569.                     final Charset set = Charset.forName(charsetName);
  570.                     address.setPersonal(name, set.name());
  571.                 }
  572.             }
  573.             // run sanity check on new InternetAddress object; if this fails
  574.             // it will throw AddressException.
  575.             address.validate();
  576.             return address;
  577.         } catch (final AddressException | UnsupportedEncodingException e) {
  578.             throw new EmailException(e);
  579.         }
  580.     }

  581.     /**
  582.      * Creates a customized MimeMessage which can be implemented by a derived class, e.g. to set the message id.
  583.      *
  584.      * @param aSession mail session to be used
  585.      * @return the newly created message
  586.      */
  587.     protected MimeMessage createMimeMessage(final Session aSession) {
  588.         return new MimeMessage(aSession);
  589.     }

  590.     /**
  591.      * Gets the authenticator.
  592.      *
  593.      * @return the authenticator.
  594.      * @since 1.6.0
  595.      */
  596.     public Authenticator getAuthenticator() {
  597.         return authenticator;
  598.     }

  599.     /**
  600.      * Gets the list of "Bcc" addresses.
  601.      *
  602.      * @return List addresses
  603.      */
  604.     public List<InternetAddress> getBccAddresses() {
  605.         return bccList;
  606.     }

  607.     /**
  608.      * Gets the "bounce address" of this email.
  609.      *
  610.      * @return the bounce address as string
  611.      * @since 1.4
  612.      */
  613.     public String getBounceAddress() {
  614.         return bounceAddress;
  615.     }

  616.     /**
  617.      * Gets the list of "CC" addresses.
  618.      *
  619.      * @return List addresses
  620.      */
  621.     public List<InternetAddress> getCcAddresses() {
  622.         return ccList;
  623.     }

  624.     /**
  625.      * Gets the Charset.
  626.      *
  627.      * @return the Charset.
  628.      * @since 1.6.0
  629.      */
  630.     public String getCharsetName() {
  631.         return charset;
  632.     }

  633.     /**
  634.      * Gets the content.
  635.      *
  636.      * @return the content.
  637.      * @since 1.6.0
  638.      */
  639.     public Object getContent() {
  640.         return content;
  641.     }

  642.     /**
  643.      * Gets the content type.
  644.      *
  645.      * @return the content type.
  646.      * @since 1.6.0
  647.      */
  648.     public String getContentType() {
  649.         return contentType;
  650.     }

  651.     /**
  652.      * Gets the email body.
  653.      *
  654.      * @return the email body.
  655.      * @since 1.6.0
  656.      */
  657.     public MimeMultipart getEmailBody() {
  658.         return emailBody;
  659.     }

  660.     /**
  661.      * Gets the sender of the email.
  662.      *
  663.      * @return from address
  664.      */
  665.     public InternetAddress getFromAddress() {
  666.         return fromAddress;
  667.     }

  668.     /**
  669.      * Gets the specified header.
  670.      *
  671.      * @param header A string with the header.
  672.      * @return The value of the header, or null if no such header.
  673.      * @since 1.5
  674.      */
  675.     public String getHeader(final String header) {
  676.         return headers.get(header);
  677.     }

  678.     /**
  679.      * Gets all headers on an Email.
  680.      *
  681.      * @return a Map of all headers.
  682.      * @since 1.5
  683.      */
  684.     public Map<String, String> getHeaders() {
  685.         return headers;
  686.     }

  687.     /**
  688.      * Gets the host name of the SMTP server,
  689.      *
  690.      * @return host name
  691.      */
  692.     public String getHostName() {
  693.         if (session != null) {
  694.             return session.getProperty(EmailConstants.MAIL_HOST);
  695.         }
  696.         if (EmailUtils.isNotEmpty(hostName)) {
  697.             return hostName;
  698.         }
  699.         return null;
  700.     }

  701.     /**
  702.      * Gets the mail session used when sending this Email, creating the Session if necessary. When a mail session is already initialized setting the session
  703.      * related properties will cause an IllegalStateException.
  704.      *
  705.      * @return A Session.
  706.      * @throws EmailException if the host name was not set
  707.      * @since 1.0
  708.      */
  709.     public Session getMailSession() throws EmailException {
  710.         if (session == null) {
  711.             final Properties properties = new Properties(System.getProperties());
  712.             properties.setProperty(EmailConstants.MAIL_TRANSPORT_PROTOCOL, EmailConstants.SMTP);

  713.             if (EmailUtils.isEmpty(hostName)) {
  714.                 hostName = properties.getProperty(EmailConstants.MAIL_HOST);
  715.             }

  716.             EmailException.checkNonEmpty(hostName, () -> "Cannot find valid hostname for mail session");

  717.             properties.setProperty(EmailConstants.MAIL_PORT, smtpPort);
  718.             properties.setProperty(EmailConstants.MAIL_HOST, hostName);
  719.             properties.setProperty(EmailConstants.MAIL_DEBUG, String.valueOf(debug));

  720.             properties.setProperty(EmailConstants.MAIL_TRANSPORT_STARTTLS_ENABLE, Boolean.toString(isStartTLSEnabled()));
  721.             properties.setProperty(EmailConstants.MAIL_TRANSPORT_STARTTLS_REQUIRED, Boolean.toString(isStartTLSRequired()));

  722.             properties.setProperty(EmailConstants.MAIL_SMTP_SEND_PARTIAL, Boolean.toString(isSendPartial()));
  723.             properties.setProperty(EmailConstants.MAIL_SMTPS_SEND_PARTIAL, Boolean.toString(isSendPartial()));

  724.             if (authenticator != null) {
  725.                 properties.setProperty(EmailConstants.MAIL_SMTP_AUTH, "true");
  726.             }

  727.             if (isSSLOnConnect()) {
  728.                 properties.setProperty(EmailConstants.MAIL_PORT, sslSmtpPort);
  729.                 properties.setProperty(EmailConstants.MAIL_SMTP_SOCKET_FACTORY_PORT, sslSmtpPort);
  730.                 properties.setProperty(EmailConstants.MAIL_SMTP_SOCKET_FACTORY_CLASS, "javax.net.ssl.SSLSocketFactory");
  731.                 properties.setProperty(EmailConstants.MAIL_SMTP_SOCKET_FACTORY_FALLBACK, "false");
  732.             }

  733.             if ((isSSLOnConnect() || isStartTLSEnabled()) && isSSLCheckServerIdentity()) {
  734.                 properties.setProperty(EmailConstants.MAIL_SMTP_SSL_CHECKSERVERIDENTITY, "true");
  735.             }

  736.             if (bounceAddress != null) {
  737.                 properties.setProperty(EmailConstants.MAIL_SMTP_FROM, bounceAddress);
  738.             }

  739.             if (socketTimeout > 0) {
  740.                 properties.setProperty(EmailConstants.MAIL_SMTP_TIMEOUT, Integer.toString(socketTimeout));
  741.             }

  742.             if (socketConnectionTimeout > 0) {
  743.                 properties.setProperty(EmailConstants.MAIL_SMTP_CONNECTIONTIMEOUT, Integer.toString(socketConnectionTimeout));
  744.             }

  745.             // changed this (back) to getInstance due to security exceptions
  746.             // caused when testing using Maven
  747.             session = Session.getInstance(properties, authenticator);
  748.         }
  749.         return session;
  750.     }

  751.     /**
  752.      * Gets the message.
  753.      *
  754.      * @return the message.
  755.      * @since 1.6.0
  756.      */
  757.     public MimeMessage getMessage() {
  758.         return message;
  759.     }

  760.     /**
  761.      * Gets the internal MimeMessage. Please note that the MimeMessage is built by the buildMimeMessage() method.
  762.      *
  763.      * @return the MimeMessage
  764.      */
  765.     public MimeMessage getMimeMessage() {
  766.         return message;
  767.     }

  768.     /**
  769.      * Gets the POP3 host.
  770.      *
  771.      * @return the POP3 host.
  772.      * @since 1.6.0
  773.      */
  774.     public String getPopHost() {
  775.         return popHost;
  776.     }

  777.     /**
  778.      * Gets the POP3 password.
  779.      *
  780.      * @return the POP3 password.
  781.      * @since 1.6.0
  782.      */
  783.     public String getPopPassword() {
  784.         return popPassword;
  785.     }

  786.     /**
  787.      * Gets the POP3 user name.
  788.      *
  789.      * @return the POP3 user name.
  790.      * @since 1.6.0
  791.      */
  792.     public String getPopUserName() {
  793.         return popUsername;
  794.     }

  795.     /**
  796.      * Gets the list of "Reply-To" addresses.
  797.      *
  798.      * @return List addresses
  799.      */
  800.     public List<InternetAddress> getReplyToAddresses() {
  801.         return replyList;
  802.     }

  803.     /**
  804.      * Gets the sent date for the email.
  805.      *
  806.      * @return date to be used as the sent date for the email
  807.      * @since 1.0
  808.      */
  809.     public Date getSentDate() {
  810.         if (sentDate == null) {
  811.             return new Date();
  812.         }
  813.         return new Date(sentDate.getTime());
  814.     }

  815.     /**
  816.      * Gets the listening port of the SMTP server.
  817.      *
  818.      * @return SMTP port
  819.      */
  820.     public String getSmtpPort() {
  821.         if (session != null) {
  822.             return session.getProperty(EmailConstants.MAIL_PORT);
  823.         }
  824.         if (EmailUtils.isNotEmpty(smtpPort)) {
  825.             return smtpPort;
  826.         }
  827.         return null;
  828.     }

  829.     /**
  830.      * Gets the socket connection timeout value in milliseconds.
  831.      *
  832.      * @return the timeout in milliseconds.
  833.      * @since 1.2
  834.      */
  835.     public int getSocketConnectionTimeout() {
  836.         return socketConnectionTimeout;
  837.     }

  838.     /**
  839.      * Gets the socket I/O timeout value in milliseconds.
  840.      *
  841.      * @return the socket I/O timeout
  842.      * @since 1.2
  843.      */
  844.     public int getSocketTimeout() {
  845.         return socketTimeout;
  846.     }

  847.     /**
  848.      * Gets the current SSL port used by the SMTP transport.
  849.      *
  850.      * @return the current SSL port used by the SMTP transport
  851.      */
  852.     public String getSslSmtpPort() {
  853.         if (session != null) {
  854.             return session.getProperty(EmailConstants.MAIL_SMTP_SOCKET_FACTORY_PORT);
  855.         }
  856.         if (EmailUtils.isNotEmpty(sslSmtpPort)) {
  857.             return sslSmtpPort;
  858.         }
  859.         return null;
  860.     }

  861.     /**
  862.      * Gets the subject of the email.
  863.      *
  864.      * @return email subject
  865.      */
  866.     public String getSubject() {
  867.         return subject;
  868.     }

  869.     /**
  870.      * Gets the list of "To" addresses.
  871.      *
  872.      * @return List addresses
  873.      */
  874.     public List<InternetAddress> getToAddresses() {
  875.         return toList;
  876.     }

  877.     /**
  878.      * Tests whether debug is on.
  879.      *
  880.      * @return whether debug is on.
  881.      * @since 1.6.0
  882.      */
  883.     public boolean isDebug() {
  884.         return debug;
  885.     }

  886.     /**
  887.      * Tests whether to use POP3 before SMTP, and if so the settings.
  888.      *
  889.      * @return whether to use POP3 before SMTP, and if so the settings.
  890.      * @since 1.6.0
  891.      */
  892.     public boolean isPopBeforeSmtp() {
  893.         return popBeforeSmtp;
  894.     }

  895.     /**
  896.      * Tests whether partial sending of email is enabled.
  897.      *
  898.      * @return true if sending partial email is enabled.
  899.      * @since 1.3.2
  900.      */
  901.     public boolean isSendPartial() {
  902.         return sendPartial;
  903.     }

  904.     /**
  905.      * Tests whether the server identity checked as specified by RFC 2595
  906.      *
  907.      * @return true if the server identity is checked.
  908.      * @since 1.3
  909.      */
  910.     public boolean isSSLCheckServerIdentity() {
  911.         return sslCheckServerIdentity;
  912.     }

  913.     /**
  914.      * Tests whether SSL/TLS encryption for the transport is currently enabled (SMTPS/POPS).
  915.      *
  916.      * @return true if SSL enabled for the transport.
  917.      * @since 1.3
  918.      */
  919.     public boolean isSSLOnConnect() {
  920.         return sslOnConnect || ssl;
  921.     }

  922.     /**
  923.      * Tests whether the client is configured to try to enable STARTTLS.
  924.      *
  925.      * @return true if using STARTTLS for authentication, false otherwise.
  926.      * @since 1.3
  927.      */
  928.     public boolean isStartTLSEnabled() {
  929.         return startTlsEnabled || tls;
  930.     }

  931.     /**
  932.      * Tests whether the client is configured to require STARTTLS.
  933.      *
  934.      * @return true if using STARTTLS for authentication, false otherwise.
  935.      * @since 1.3
  936.      */
  937.     public boolean isStartTLSRequired() {
  938.         return startTlsRequired;
  939.     }

  940.     /**
  941.      * Sends the email. Internally we build a MimeMessage which is afterwards sent to the SMTP server.
  942.      *
  943.      * @return the message id of the underlying MimeMessage
  944.      * @throws IllegalStateException if the MimeMessage was already built, that is, {@link #buildMimeMessage()} was already called
  945.      * @throws EmailException        the sending failed
  946.      */
  947.     public String send() throws EmailException {
  948.         buildMimeMessage();
  949.         return sendMimeMessage();
  950.     }

  951.     /**
  952.      * Sends the previously created MimeMessage to the SMTP server.
  953.      *
  954.      * @return the message id of the underlying MimeMessage
  955.      * @throws IllegalArgumentException if the MimeMessage has not been created
  956.      * @throws EmailException           the sending failed
  957.      */
  958.     public String sendMimeMessage() throws EmailException {
  959.         Objects.requireNonNull(message, "MimeMessage has not been created yet");
  960.         try {
  961.             Transport.send(message);
  962.             return message.getMessageID();
  963.         } catch (final Throwable t) {
  964.             throw new EmailException("Sending the email to the following server failed : " + this.getHostName() + ":" + getSmtpPort(), t);
  965.         }
  966.     }

  967.     /**
  968.      * Sets the userName and password if authentication is needed. If this method is not used, no authentication will be performed.
  969.      * <p>
  970.      * This method will create a new instance of {@code DefaultAuthenticator} using the supplied parameters.
  971.      * </p>
  972.      *
  973.      * @param userName User name for the SMTP server
  974.      * @param password password for the SMTP server
  975.      * @see DefaultAuthenticator
  976.      * @see #setAuthenticator
  977.      * @since 1.0
  978.      */
  979.     public void setAuthentication(final String userName, final String password) {
  980.         this.setAuthenticator(new DefaultAuthenticator(userName, password));
  981.     }

  982.     /**
  983.      * Sets the {@code Authenticator} to be used when authentication is requested from the mail server.
  984.      * <p>
  985.      * This method should be used when your outgoing mail server requires authentication. Your mail server must also support RFC2554.
  986.      * </p>
  987.      *
  988.      * @param authenticator the {@code Authenticator} object.
  989.      * @see Authenticator
  990.      * @since 1.0
  991.      */
  992.     public void setAuthenticator(final Authenticator authenticator) {
  993.         this.authenticator = authenticator;
  994.     }

  995.     /**
  996.      * Sets a list of "BCC" addresses. All elements in the specified {@code Collection} are expected to be of type {@code java.mail.internet.InternetAddress}.
  997.      *
  998.      * @param collection collection of {@code InternetAddress} objects
  999.      * @return An Email.
  1000.      * @throws EmailException Indicates an invalid email address
  1001.      * @see javax.mail.internet.InternetAddress
  1002.      * @since 1.0
  1003.      */
  1004.     public Email setBcc(final Collection<InternetAddress> collection) throws EmailException {
  1005.         EmailException.checkNonEmpty(collection, () -> "BCC list invalid");
  1006.         bccList = new ArrayList<>(collection);
  1007.         return this;
  1008.     }

  1009.     /**
  1010.      * 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
  1011.      * the address specified with the System property "mail.smtp.from", or if that value is not set, then to the "from" address.
  1012.      *
  1013.      * @param email A String.
  1014.      * @return An Email.
  1015.      * @throws IllegalStateException if the mail session is already initialized
  1016.      * @since 1.0
  1017.      */
  1018.     public Email setBounceAddress(final String email) {
  1019.         checkSessionAlreadyInitialized();
  1020.         if (!EmailUtils.isEmpty(email)) {
  1021.             try {
  1022.                 bounceAddress = createInternetAddress(email, null, charset).getAddress();
  1023.             } catch (final EmailException e) {
  1024.                 // Can't throw 'EmailException' to keep backward-compatibility
  1025.                 throw new IllegalArgumentException("Failed to set the bounce address : " + email, e);
  1026.             }
  1027.         } else {
  1028.             bounceAddress = email;
  1029.         }

  1030.         return this;
  1031.     }

  1032.     /**
  1033.      * Sets a list of "CC" addresses. All elements in the specified {@code Collection} are expected to be of type {@code java.mail.internet.InternetAddress}.
  1034.      *
  1035.      * @param collection collection of {@code InternetAddress} objects.
  1036.      * @return An Email.
  1037.      * @throws EmailException Indicates an invalid email address.
  1038.      * @see javax.mail.internet.InternetAddress
  1039.      * @since 1.0
  1040.      */
  1041.     public Email setCc(final Collection<InternetAddress> collection) throws EmailException {
  1042.         EmailException.checkNonEmpty(collection, () -> "CC list invalid");
  1043.         ccList = new ArrayList<>(collection);
  1044.         return this;
  1045.     }

  1046.     /**
  1047.      * Sets the charset of the message. Please note that you should set the charset before adding the message content.
  1048.      *
  1049.      * @param charset A String.
  1050.      * @throws java.nio.charset.IllegalCharsetNameException if the charset name is invalid
  1051.      * @throws java.nio.charset.UnsupportedCharsetException if no support for the named charset exists in the current JVM
  1052.      * @since 1.0
  1053.      */
  1054.     public void setCharset(final String charset) {
  1055.         final Charset set = Charset.forName(charset);
  1056.         this.charset = set.name();
  1057.     }

  1058.     /**
  1059.      * Sets the emailBody to a MimeMultiPart
  1060.      *
  1061.      * @param mimeMultipart aMimeMultipart
  1062.      * @since 1.0
  1063.      */
  1064.     public void setContent(final MimeMultipart mimeMultipart) {
  1065.         this.emailBody = mimeMultipart;
  1066.     }

  1067.     /**
  1068.      * Sets the content.
  1069.      *
  1070.      * @param content the content.
  1071.      * @return {@code this} instance.
  1072.      * @since 1.6.0
  1073.      */
  1074.     public Email setContent(final Object content) {
  1075.         this.content = content;
  1076.         return this;
  1077.     }

  1078.     /**
  1079.      * Sets the content and contentType.
  1080.      *
  1081.      * @param content     content.
  1082.      * @param contentType content type.
  1083.      * @since 1.0
  1084.      */
  1085.     public void setContent(final Object content, final String contentType) {
  1086.         this.content = content;
  1087.         updateContentType(contentType);
  1088.     }

  1089.     /**
  1090.      * Sets the content type.
  1091.      *
  1092.      * @param contentType the content type.
  1093.      * @return {@code this} instance.
  1094.      * @since 1.6.0
  1095.      */
  1096.     public Email setContentType(final String contentType) {
  1097.         this.contentType = contentType;
  1098.         return this;
  1099.     }

  1100.     /**
  1101.      * Sets the display of debug information.
  1102.      *
  1103.      * @param debug A boolean.
  1104.      * @since 1.0
  1105.      */
  1106.     public void setDebug(final boolean debug) {
  1107.         this.debug = debug;
  1108.     }

  1109.     /**
  1110.      * 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
  1111.      * 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
  1112.      * characters; otherwise, it is used as is.
  1113.      *
  1114.      * @param email A String.
  1115.      * @return An Email.
  1116.      * @throws EmailException Indicates an invalid email address.
  1117.      * @since 1.0
  1118.      */
  1119.     public Email setFrom(final String email) throws EmailException {
  1120.         return setFrom(email, null);
  1121.     }

  1122.     /**
  1123.      * 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
  1124.      * {@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;
  1125.      * otherwise, it is used as is.
  1126.      *
  1127.      * @param email A String.
  1128.      * @param name  A String.
  1129.      * @return An Email.
  1130.      * @throws EmailException Indicates an invalid email address.
  1131.      * @since 1.0
  1132.      */
  1133.     public Email setFrom(final String email, final String name) throws EmailException {
  1134.         return setFrom(email, name, charset);
  1135.     }

  1136.     /**
  1137.      * Sets the FROM field of the email to use the specified address, personal name, and charset encoding for the name.
  1138.      *
  1139.      * @param email   A String.
  1140.      * @param name    A String.
  1141.      * @param charset The charset to encode the name with.
  1142.      * @return An Email.
  1143.      * @throws EmailException Indicates an invalid email address or charset.
  1144.      * @since 1.1
  1145.      */
  1146.     public Email setFrom(final String email, final String name, final String charset) throws EmailException {
  1147.         fromAddress = createInternetAddress(email, name, charset);
  1148.         return this;
  1149.     }

  1150.     /**
  1151.      * Sets the From address.
  1152.      *
  1153.      * @param fromAddress the From address.
  1154.      * @return {@code this} instance.
  1155.      * @since 1.6.0
  1156.      */
  1157.     public Email setFromAddress(final InternetAddress fromAddress) {
  1158.         this.fromAddress = fromAddress;
  1159.         return this;

  1160.     }

  1161.     /**
  1162.      * Sets the mail headers. Example:
  1163.      *
  1164.      * X-Mailer: Sendmail, X-Priority: 1( highest ) or 2( high ) 3( normal ) 4( low ) and 5( lowest ) Disposition-Notification-To: user@domain.net
  1165.      *
  1166.      * @param map A Map.
  1167.      * @throws IllegalArgumentException if either of the provided header / value is null or empty
  1168.      * @since 1.0
  1169.      */
  1170.     public void setHeaders(final Map<String, String> map) {
  1171.         headers.clear();
  1172.         for (final Map.Entry<String, String> entry : map.entrySet()) {
  1173.             addHeader(entry.getKey(), entry.getValue());
  1174.         }
  1175.     }

  1176.     /**
  1177.      * Sets the hostname of the outgoing mail server.
  1178.      *
  1179.      * @param hostName aHostName
  1180.      * @throws IllegalStateException if the mail session is already initialized
  1181.      * @since 1.0
  1182.      */
  1183.     public void setHostName(final String hostName) {
  1184.         checkSessionAlreadyInitialized();
  1185.         this.hostName = hostName;
  1186.     }

  1187.     /**
  1188.      * 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
  1189.      * with a DefaultAuthenticator. This is a convenience but might come unexpected.
  1190.      *
  1191.      * 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
  1192.      * existing mail session (as expected).
  1193.      *
  1194.      * @param session mail session to be used
  1195.      * @throws NullPointerException if {@code aSession} is {@code null}
  1196.      * @since 1.0
  1197.      */
  1198.     public void setMailSession(final Session session) {
  1199.         Objects.requireNonNull(session, "no mail session supplied");

  1200.         final Properties sessionProperties = session.getProperties();
  1201.         final String auth = sessionProperties.getProperty(EmailConstants.MAIL_SMTP_AUTH);

  1202.         if (Boolean.parseBoolean(auth)) {
  1203.             final String userName = sessionProperties.getProperty(EmailConstants.MAIL_SMTP_USER);
  1204.             final String password = sessionProperties.getProperty(EmailConstants.MAIL_SMTP_PASSWORD);

  1205.             if (EmailUtils.isNotEmpty(userName) && EmailUtils.isNotEmpty(password)) {
  1206.                 // only create a new mail session with an authenticator if
  1207.                 // authentication is required and no user name is given
  1208.                 authenticator = new DefaultAuthenticator(userName, password);
  1209.                 this.session = Session.getInstance(sessionProperties, authenticator);
  1210.             } else {
  1211.                 // assume that the given mail session contains a working authenticator
  1212.                 this.session = session;
  1213.             }
  1214.         } else {
  1215.             this.session = session;
  1216.         }
  1217.     }

  1218.     /**
  1219.      * Sets a mail Session object from a JNDI directory.
  1220.      *
  1221.      * @param jndiName name of JNDI resource (javax.mail.Session type), resource if searched in java:comp/env if name does not start with "java:"
  1222.      * @throws IllegalArgumentException if the JNDI name is null or empty
  1223.      * @throws NamingException          if the resource cannot be retrieved from JNDI directory
  1224.      * @since 1.1
  1225.      */
  1226.     public void setMailSessionFromJNDI(final String jndiName) throws NamingException {
  1227.         if (EmailUtils.isEmpty(jndiName)) {
  1228.             throw new IllegalArgumentException("JNDI name missing");
  1229.         }
  1230.         Context ctx = null;
  1231.         if (jndiName.startsWith("java:")) {
  1232.             ctx = new InitialContext();
  1233.         } else {
  1234.             ctx = (Context) new InitialContext().lookup("java:comp/env");

  1235.         }
  1236.         setMailSession((Session) ctx.lookup(jndiName));
  1237.     }

  1238.     /**
  1239.      * Sets the MIME message.
  1240.      *
  1241.      * @param message the MIME message.
  1242.      */
  1243.     public void setMessage(final MimeMessage message) {
  1244.         this.message = message;
  1245.     }

  1246.     /**
  1247.      * Sets the content of the mail. It should be overridden by the subclasses.
  1248.      *
  1249.      * @param msg A String.
  1250.      * @return An Email.
  1251.      * @throws EmailException generic exception.
  1252.      * @since 1.0
  1253.      */
  1254.     public abstract Email setMsg(String msg) throws EmailException;

  1255.     /**
  1256.      * Sets whether to use POP3 before SMTP, and if so the settings.
  1257.      *
  1258.      * @param popBeforeSmtp whether to use POP3 before SMTP, and if so the settings.
  1259.      * @return {@code this} instance.
  1260.      * @since 1.6.0
  1261.      */
  1262.     public Email setPopBeforeSmtp(final boolean popBeforeSmtp) {
  1263.         this.popBeforeSmtp = popBeforeSmtp;
  1264.         return this;

  1265.     }

  1266.     /**
  1267.      * Sets details regarding "POP3 before SMTP" authentication.
  1268.      *
  1269.      * @param popBeforeSmtp Whether or not to log into POP3 server before sending mail.
  1270.      * @param popHost       The POP3 host to use.
  1271.      * @param popUserName   The POP3 user name.
  1272.      * @param popPassword   The POP3 password.
  1273.      * @since 1.0
  1274.      */
  1275.     public void setPopBeforeSmtp(final boolean popBeforeSmtp, final String popHost, final String popUserName, final String popPassword) {
  1276.         this.popBeforeSmtp = popBeforeSmtp;
  1277.         this.popHost = popHost;
  1278.         this.popUsername = popUserName;
  1279.         this.popPassword = popPassword;
  1280.     }

  1281.     /**
  1282.      * Sets the POP3 host.
  1283.      *
  1284.      * @param popHost The POP3 host.
  1285.      * @return {@code this} instance.
  1286.      * @since 1.6.0
  1287.      */
  1288.     public Email setPopHost(final String popHost) {
  1289.         this.popHost = popHost;
  1290.         return this;

  1291.     }

  1292.     /**
  1293.      * Sets the POP3 password.
  1294.      *
  1295.      * @param popPassword the POP3 password.
  1296.      * @return {@code this} instance.
  1297.      * @since 1.6.0
  1298.      */
  1299.     public Email setPopPassword(final String popPassword) {
  1300.         this.popPassword = popPassword;
  1301.         return this;

  1302.     }

  1303.     /**
  1304.      * Sets the POP3 user name.
  1305.      *
  1306.      * @param popUserName the POP3 user name.
  1307.      * @return {@code this} instance.
  1308.      * @since 1.6.0
  1309.      */
  1310.     public Email setPopUsername(final String popUserName) {
  1311.         this.popUsername = popUserName;
  1312.         return this;

  1313.     }

  1314.     /**
  1315.      * Sets a list of reply to addresses. All elements in the specified {@code Collection} are expected to be of type
  1316.      * {@code java.mail.internet.InternetAddress}.
  1317.      *
  1318.      * @param collection collection of {@code InternetAddress} objects
  1319.      * @return An Email.
  1320.      * @throws EmailException Indicates an invalid email address
  1321.      * @see javax.mail.internet.InternetAddress
  1322.      * @since 1.1
  1323.      */
  1324.     public Email setReplyTo(final Collection<InternetAddress> collection) throws EmailException {
  1325.         EmailException.checkNonEmpty(collection, () -> "Reply to list invalid");
  1326.         replyList = new ArrayList<>(collection);
  1327.         return this;
  1328.     }

  1329.     /**
  1330.      * Sets whether the email is partially send in case of invalid addresses.
  1331.      * <p>
  1332.      * 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
  1333.      * send mode is enabled (emails to valid addresses will be transmitted). In case the email server does not reject invalid addresses immediately, but return
  1334.      * a bounce message, no exception will be thrown by the {@link #send()} method.
  1335.      * </p>
  1336.      *
  1337.      * @param sendPartial whether to enable partial send mode
  1338.      * @return An Email.
  1339.      * @throws IllegalStateException if the mail session is already initialized
  1340.      * @since 1.3.2
  1341.      */
  1342.     public Email setSendPartial(final boolean sendPartial) {
  1343.         checkSessionAlreadyInitialized();
  1344.         this.sendPartial = sendPartial;
  1345.         return this;
  1346.     }

  1347.     /**
  1348.      * Sets the sent date for the email. The sent date will default to the current date if not explicitly set.
  1349.      *
  1350.      * @param date Date to use as the sent date on the email
  1351.      * @since 1.0
  1352.      */
  1353.     public void setSentDate(final Date date) {
  1354.         if (date != null) {
  1355.             // create a separate instance to keep findbugs happy
  1356.             sentDate = new Date(date.getTime());
  1357.         }
  1358.     }

  1359.     /**
  1360.      * Sets the non-SSL port number of the outgoing mail server.
  1361.      *
  1362.      * @param portNumber aPortNumber
  1363.      * @throws IllegalArgumentException if the port number is &lt; 1
  1364.      * @throws IllegalStateException    if the mail session is already initialized
  1365.      * @since 1.0
  1366.      * @see #setSslSmtpPort(String)
  1367.      */
  1368.     public void setSmtpPort(final int portNumber) {
  1369.         checkSessionAlreadyInitialized();
  1370.         if (portNumber < 1) {
  1371.             throw new IllegalArgumentException("Cannot connect to a port number that is less than 1 ( " + portNumber + " )");
  1372.         }
  1373.         this.smtpPort = Integer.toString(portNumber);
  1374.     }

  1375.     /**
  1376.      * Sets the socket connection timeout value in milliseconds. Default is a 60 second timeout.
  1377.      *
  1378.      * @param socketConnectionTimeout the connection timeout
  1379.      * @throws IllegalStateException if the mail session is already initialized
  1380.      * @since 1.6.0
  1381.      */
  1382.     public void setSocketConnectionTimeout(final Duration socketConnectionTimeout) {
  1383.         checkSessionAlreadyInitialized();
  1384.         this.socketConnectionTimeout = Math.toIntExact(socketConnectionTimeout.toMillis());
  1385.     }

  1386.     /**
  1387.      * Sets the socket I/O timeout value in milliseconds. Default is 60 second timeout.
  1388.      *
  1389.      * @param socketTimeout the socket I/O timeout
  1390.      * @throws IllegalStateException if the mail session is already initialized
  1391.      * @since 1.6.0
  1392.      */
  1393.     public void setSocketTimeout(final Duration socketTimeout) {
  1394.         checkSessionAlreadyInitialized();
  1395.         this.socketTimeout = Math.toIntExact(socketTimeout.toMillis());
  1396.     }

  1397.     /**
  1398.      * Sets whether the server identity is checked as specified by RFC 2595
  1399.      *
  1400.      * @param sslCheckServerIdentity whether to enable server identity check
  1401.      * @return An Email.
  1402.      * @throws IllegalStateException if the mail session is already initialized
  1403.      * @since 1.3
  1404.      */
  1405.     public Email setSSLCheckServerIdentity(final boolean sslCheckServerIdentity) {
  1406.         checkSessionAlreadyInitialized();
  1407.         this.sslCheckServerIdentity = sslCheckServerIdentity;
  1408.         return this;
  1409.     }

  1410.     /**
  1411.      * Sets whether SSL/TLS encryption should be enabled for the SMTP transport upon connection (SMTPS/POPS). Takes precedence over
  1412.      * {@link #setStartTLSRequired(boolean)}
  1413.      * <p>
  1414.      * Defaults to {@link #sslSmtpPort}; can be overridden by using {@link #setSslSmtpPort(String)}
  1415.      * </p>
  1416.      *
  1417.      * @param ssl whether to enable the SSL transport
  1418.      * @return An Email.
  1419.      * @throws IllegalStateException if the mail session is already initialized
  1420.      * @since 1.3
  1421.      */
  1422.     public Email setSSLOnConnect(final boolean ssl) {
  1423.         checkSessionAlreadyInitialized();
  1424.         this.sslOnConnect = ssl;
  1425.         this.ssl = ssl;
  1426.         return this;
  1427.     }

  1428.     /**
  1429.      * Sets the SSL port to use for the SMTP transport. Defaults to the standard port, 465.
  1430.      *
  1431.      * @param sslSmtpPort the SSL port to use for the SMTP transport
  1432.      * @throws IllegalStateException if the mail session is already initialized
  1433.      * @see #setSmtpPort(int)
  1434.      */
  1435.     public void setSslSmtpPort(final String sslSmtpPort) {
  1436.         checkSessionAlreadyInitialized();
  1437.         this.sslSmtpPort = sslSmtpPort;
  1438.     }

  1439.     /**
  1440.      * Sets or disable the STARTTLS encryption.
  1441.      *
  1442.      * @param startTlsEnabled true if STARTTLS requested, false otherwise
  1443.      * @return An Email.
  1444.      * @throws IllegalStateException if the mail session is already initialized
  1445.      * @since 1.3
  1446.      */
  1447.     public Email setStartTLSEnabled(final boolean startTlsEnabled) {
  1448.         checkSessionAlreadyInitialized();
  1449.         this.startTlsEnabled = startTlsEnabled;
  1450.         this.tls = startTlsEnabled;
  1451.         return this;
  1452.     }

  1453.     /**
  1454.      * Sets or disable the required STARTTLS encryption.
  1455.      * <p>
  1456.      * Defaults to {@link #smtpPort}; can be overridden by using {@link #setSmtpPort(int)}
  1457.      * </p>
  1458.      *
  1459.      * @param startTlsRequired true if STARTTLS requested, false otherwise
  1460.      * @return An Email.
  1461.      * @throws IllegalStateException if the mail session is already initialized
  1462.      * @since 1.3
  1463.      */
  1464.     public Email setStartTLSRequired(final boolean startTlsRequired) {
  1465.         checkSessionAlreadyInitialized();
  1466.         this.startTlsRequired = startTlsRequired;
  1467.         return this;
  1468.     }

  1469.     /**
  1470.      * Sets the email subject. Replaces end-of-line characters with spaces.
  1471.      *
  1472.      * @param aSubject A String.
  1473.      * @return An Email.
  1474.      * @since 1.0
  1475.      */
  1476.     public Email setSubject(final String aSubject) {
  1477.         this.subject = EmailUtils.replaceEndOfLineCharactersWithSpaces(aSubject);
  1478.         return this;
  1479.     }

  1480.     /**
  1481.      * Sets a list of "TO" addresses. All elements in the specified {@code Collection} are expected to be of type {@code java.mail.internet.InternetAddress}.
  1482.      *
  1483.      * @param collection collection of {@code InternetAddress} objects.
  1484.      * @return An Email.
  1485.      * @throws EmailException Indicates an invalid email address.
  1486.      * @see javax.mail.internet.InternetAddress
  1487.      * @since 1.0
  1488.      */
  1489.     public Email setTo(final Collection<InternetAddress> collection) throws EmailException {
  1490.         EmailException.checkNonEmpty(collection, () -> "To list invalid");
  1491.         this.toList = new ArrayList<>(collection);
  1492.         return this;
  1493.     }

  1494.     /**
  1495.      * Converts to copy List of known InternetAddress objects into an array.
  1496.      *
  1497.      * @param list A List.
  1498.      * @return An InternetAddress[].
  1499.      * @since 1.0
  1500.      */
  1501.     protected InternetAddress[] toInternetAddressArray(final List<InternetAddress> list) {
  1502.         return list.toArray(EMPTY_INTERNET_ADDRESS_ARRAY);
  1503.     }

  1504.     /**
  1505.      * Updates the contentType.
  1506.      *
  1507.      * @param contentType aContentType
  1508.      * @since 1.2
  1509.      */
  1510.     public void updateContentType(final String contentType) {
  1511.         if (EmailUtils.isEmpty(contentType)) {
  1512.             this.contentType = null;
  1513.         } else {
  1514.             // set the content type
  1515.             this.contentType = contentType;
  1516.             // set the charset if the input was properly formed
  1517.             final String strMarker = "; charset=";
  1518.             int charsetPos = EmailUtils.toLower(contentType).indexOf(strMarker);
  1519.             if (charsetPos != -1) {
  1520.                 // find the next space (after the marker)
  1521.                 charsetPos += strMarker.length();
  1522.                 final int intCharsetEnd = EmailUtils.toLower(contentType).indexOf(" ", charsetPos);
  1523.                 if (intCharsetEnd != -1) {
  1524.                     this.charset = contentType.substring(charsetPos, intCharsetEnd);
  1525.                 } else {
  1526.                     this.charset = contentType.substring(charsetPos);
  1527.                 }
  1528.             } else if (this.contentType.startsWith("text/") && EmailUtils.isNotEmpty(this.charset)) {
  1529.                 // use the default charset, if one exists, for messages
  1530.                 // whose content-type is some form of text.
  1531.                 final StringBuilder contentTypeBuf = new StringBuilder(this.contentType);
  1532.                 contentTypeBuf.append(strMarker);
  1533.                 contentTypeBuf.append(this.charset);
  1534.                 this.contentType = contentTypeBuf.toString();
  1535.             }
  1536.         }
  1537.     }
  1538. }