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