    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 &lt; 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}