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 */
017 package org.apache.commons.mail;
018
019 import java.io.UnsupportedEncodingException;
020 import java.nio.charset.Charset;
021 import java.util.ArrayList;
022 import java.util.Collection;
023 import java.util.Date;
024 import java.util.HashMap;
025 import java.util.Iterator;
026 import java.util.List;
027 import java.util.Map;
028 import java.util.Properties;
029
030 import javax.mail.Authenticator;
031 import javax.mail.Message;
032 import javax.mail.MessagingException;
033 import javax.mail.Session;
034 import javax.mail.Store;
035 import javax.mail.Transport;
036 import javax.mail.internet.AddressException;
037 import javax.mail.internet.InternetAddress;
038 import javax.mail.internet.MimeMessage;
039 import javax.mail.internet.MimeMultipart;
040 import javax.naming.Context;
041 import javax.naming.InitialContext;
042 import javax.naming.NamingException;
043
044 /**
045 * The base class for all email messages. This class sets the
046 * sender's email & name, receiver's email & name, subject, and the
047 * sent date. Subclasses are responsible for setting the message
048 * body.
049 *
050 * @since 1.0
051 * @author <a href="mailto:quintonm@bellsouth.net">Quinton McCombs</a>
052 * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a>
053 * @author <a href="mailto:frank.kim@clearink.com">Frank Y. Kim</a>
054 * @author <a href="mailto:bmclaugh@algx.net">Brett McLaughlin</a>
055 * @author <a href="mailto:greg@shwoop.com">Greg Ritter</a>
056 * @author <a href="mailto:unknown">Regis Koenig</a>
057 * @author <a href="mailto:colin.chalmers@maxware.nl">Colin Chalmers</a>
058 * @author <a href="mailto:matthias@wessendorf.net">Matthias Wessendorf</a>
059 * @author <a href="mailto:corey.scott@gmail.com">Corey Scott</a>
060 * @version $Revision: 577476 $ $Date: 2007-09-19 16:50:30 -0700 (Wed, 19 Sep 2007) $
061 * @version $Id: Email.java 577476 2007-09-19 23:50:30Z bspeakmon $
062 */
063 public abstract class Email
064 {
065 /** Constants used by Email classes. */
066
067 /** */
068 public static final String SENDER_EMAIL = "sender.email";
069 /** */
070 public static final String SENDER_NAME = "sender.name";
071 /** */
072 public static final String RECEIVER_EMAIL = "receiver.email";
073 /** */
074 public static final String RECEIVER_NAME = "receiver.name";
075 /** */
076 public static final String EMAIL_SUBJECT = "email.subject";
077 /** */
078 public static final String EMAIL_BODY = "email.body";
079 /** */
080 public static final String CONTENT_TYPE = "content.type";
081
082 /** */
083 public static final String MAIL_HOST = "mail.smtp.host";
084 /** */
085 public static final String MAIL_PORT = "mail.smtp.port";
086 /** */
087 public static final String MAIL_SMTP_FROM = "mail.smtp.from";
088 /** */
089 public static final String MAIL_SMTP_AUTH = "mail.smtp.auth";
090 /** */
091 public static final String MAIL_SMTP_USER = "mail.smtp.user";
092 /** */
093 public static final String MAIL_SMTP_PASSWORD = "mail.smtp.password";
094 /** */
095 public static final String MAIL_TRANSPORT_PROTOCOL =
096 "mail.transport.protocol";
097 /**
098 * @since 1.1
099 */
100 public static final String MAIL_TRANSPORT_TLS = "mail.smtp.starttls.enable";
101 /** */
102 public static final String MAIL_SMTP_SOCKET_FACTORY_FALLBACK = "mail.smtp.socketFactory.fallback";
103 /** */
104 public static final String MAIL_SMTP_SOCKET_FACTORY_CLASS = "mail.smtp.socketFactory.class";
105 /** */
106 public static final String MAIL_SMTP_SOCKET_FACTORY_PORT = "mail.smtp.socketFactory.port";
107 /** */
108 public static final String SMTP = "smtp";
109 /** */
110 public static final String TEXT_HTML = "text/html";
111 /** */
112 public static final String TEXT_PLAIN = "text/plain";
113 /** */
114 public static final String ATTACHMENTS = "attachments";
115 /** */
116 public static final String FILE_SERVER = "file.server";
117 /** */
118 public static final String MAIL_DEBUG = "mail.debug";
119
120 /** */
121 public static final String KOI8_R = "koi8-r";
122 /** */
123 public static final String ISO_8859_1 = "iso-8859-1";
124 /** */
125 public static final String US_ASCII = "us-ascii";
126
127 /** The email message to send. */
128 protected MimeMessage message;
129
130 /** The charset to use for this message */
131 protected String charset;
132
133 /** The Address of the sending party, mandatory */
134 protected InternetAddress fromAddress;
135
136 /** The Subject */
137 protected String subject;
138
139 /** An attachment */
140 protected MimeMultipart emailBody;
141
142 /** The content */
143 protected Object content;
144
145 /** The content type */
146 protected String contentType;
147
148 /** Set session debugging on or off */
149 protected boolean debug;
150
151 /** Sent date */
152 protected Date sentDate;
153
154 /**
155 * Instance of an <code>Authenticator</code> object that will be used
156 * when authentication is requested from the mail server.
157 */
158 protected Authenticator authenticator;
159
160 /**
161 * The hostname of the mail server with which to connect. If null will try
162 * to get property from system.properties. If still null, quit
163 */
164 protected String hostName;
165
166 /**
167 * The port number of the mail server to connect to.
168 * Defaults to the standard port ( 25 ).
169 */
170 protected String smtpPort = "25";
171
172 /**
173 * The port number of the SSL enabled SMTP server;
174 * defaults to the standard port, 465.
175 */
176 protected String sslSmtpPort = "465";
177
178 /** List of "to" email adresses */
179 protected List toList = new ArrayList();
180
181 /** List of "cc" email adresses */
182 protected List ccList = new ArrayList();
183
184 /** List of "bcc" email adresses */
185 protected List bccList = new ArrayList();
186
187 /** List of "replyTo" email adresses */
188 protected List replyList = new ArrayList();
189
190 /**
191 * Address to which undeliverable mail should be sent.
192 * Because this is handled by JavaMail as a String property
193 * in the mail session, this property is of type <code>String</code>
194 * rather than <code>InternetAddress</code>.
195 */
196 protected String bounceAddress;
197
198 /**
199 * Used to specify the mail headers. Example:
200 *
201 * X-Mailer: Sendmail, X-Priority: 1( highest )
202 * or 2( high ) 3( normal ) 4( low ) and 5( lowest )
203 * Disposition-Notification-To: user@domain.net
204 */
205 protected Map headers = new HashMap();
206
207 /**
208 * Used to determine whether to use pop3 before smtp, and if so the settings.
209 */
210 protected boolean popBeforeSmtp;
211 /** the host name of the pop3 server */
212 protected String popHost;
213 /** the user name to log into the pop3 server */
214 protected String popUsername;
215 /** the password to log into the pop3 server */
216 protected String popPassword;
217
218 /** does server require TLS encryption for authentication */
219 protected boolean tls;
220 /** does the current transport use SSL encryption? */
221 protected boolean ssl;
222
223 /** The Session to mail with */
224 private Session session;
225
226 /**
227 * Setting to true will enable the display of debug information.
228 *
229 * @param d A boolean.
230 * @since 1.0
231 */
232 public void setDebug(boolean d)
233 {
234 this.debug = d;
235 }
236
237 /**
238 * Sets the userName and password if authentication is needed. If this
239 * method is not used, no authentication will be performed.
240 * <p>
241 * This method will create a new instance of
242 * <code>DefaultAuthenticator</code> using the supplied parameters.
243 *
244 * @param userName User name for the SMTP server
245 * @param password password for the SMTP server
246 * @see DefaultAuthenticator
247 * @see #setAuthenticator
248 * @since 1.0
249 */
250 public void setAuthentication(String userName, String password)
251 {
252 this.authenticator = new DefaultAuthenticator(userName, password);
253 this.setAuthenticator(this.authenticator);
254 }
255
256 /**
257 * Sets the <code>Authenticator</code> to be used when authentication
258 * is requested from the mail server.
259 * <p>
260 * This method should be used when your outgoing mail server requires
261 * authentication. Your mail server must also support RFC2554.
262 *
263 * @param newAuthenticator the <code>Authenticator</code> object.
264 * @see Authenticator
265 * @since 1.0
266 */
267 public void setAuthenticator(Authenticator newAuthenticator)
268 {
269 this.authenticator = newAuthenticator;
270 }
271
272 /**
273 * Set the charset of the message.
274 *
275 * @param newCharset A String.
276 * @throws java.nio.charset.IllegalCharsetNameException if the charset name is invalid
277 * @throws java.nio.charset.UnsupportedCharsetException if no support for the named charset
278 * exists in the current JVM
279 * @since 1.0
280 */
281 public void setCharset(String newCharset)
282 {
283 Charset set = Charset.forName(newCharset);
284 this.charset = set.name();
285 }
286
287 /**
288 * Set the emailBody to a MimeMultiPart
289 *
290 * @param aMimeMultipart aMimeMultipart
291 * @since 1.0
292 */
293 public void setContent(MimeMultipart aMimeMultipart)
294 {
295 this.emailBody = aMimeMultipart;
296 }
297
298 /**
299 * Set the content & contentType
300 *
301 * @param aObject aObject
302 * @param aContentType aContentType
303 * @since 1.0
304 */
305 public void setContent(Object aObject, String aContentType)
306 {
307 this.content = aObject;
308 if (EmailUtils.isEmpty(aContentType))
309 {
310 this.contentType = null;
311 }
312 else
313 {
314 // set the content type
315 this.contentType = aContentType;
316
317 // set the charset if the input was properly formed
318 String strMarker = "; charset=";
319 int charsetPos = aContentType.toLowerCase().indexOf(strMarker);
320
321 if (charsetPos != -1)
322 {
323 // find the next space (after the marker)
324 charsetPos += strMarker.length();
325 int intCharsetEnd =
326 aContentType.toLowerCase().indexOf(" ", charsetPos);
327
328 if (intCharsetEnd != -1)
329 {
330 this.charset =
331 aContentType.substring(charsetPos, intCharsetEnd);
332 }
333 else
334 {
335 this.charset = aContentType.substring(charsetPos);
336 }
337 }
338 else
339 {
340 // use the default charset, if one exists, for messages
341 // whose content-type is some form of text.
342 if (this.contentType.startsWith("text/") && EmailUtils.isNotEmpty(this.charset))
343 {
344 StringBuffer contentTypeBuf = new StringBuffer(this.contentType);
345 contentTypeBuf.append(strMarker);
346 contentTypeBuf.append(this.charset);
347 this.contentType = contentTypeBuf.toString();
348 }
349 }
350 }
351 }
352
353 /**
354 * Set the hostname of the outgoing mail server
355 *
356 * @param aHostName aHostName
357 * @since 1.0
358 */
359 public void setHostName(String aHostName)
360 {
361 this.hostName = aHostName;
362 }
363
364 /**
365 * Set or disable the TLS encryption
366 *
367 * @param withTLS true if TLS needed, false otherwise
368 * @since 1.1
369 */
370 public void setTLS(boolean withTLS)
371 {
372 this.tls = withTLS;
373 }
374
375 /**
376 * Set the port number of the outgoing mail server.
377 * @param aPortNumber aPortNumber
378 * @since 1.0
379 */
380 public void setSmtpPort(int aPortNumber)
381 {
382 if (aPortNumber < 1)
383 {
384 throw new IllegalArgumentException(
385 "Cannot connect to a port number that is less than 1 ( "
386 + aPortNumber
387 + " )");
388 }
389
390 this.smtpPort = Integer.toString(aPortNumber);
391 }
392
393 /**
394 * Supply a mail Session object to use
395 * @param aSession mail session to be used
396 * @since 1.0
397 */
398 public void setMailSession(Session aSession)
399 {
400 Properties sessionProperties = aSession.getProperties();
401 String auth = sessionProperties.getProperty(MAIL_SMTP_AUTH);
402 if ("true".equalsIgnoreCase(auth))
403 {
404 String userName = sessionProperties.getProperty(MAIL_SMTP_USER);
405 String password = sessionProperties.getProperty(MAIL_SMTP_PASSWORD);
406 this.authenticator = new DefaultAuthenticator(userName, password);
407 this.session = Session.getInstance(sessionProperties, this.authenticator);
408 }
409 else
410 {
411 this.session = aSession;
412 }
413 }
414
415 /**
416 * Supply a mail Session object from a JNDI directory
417 * @param jndiName name of JNDI ressource (javax.mail.Session type), ressource
418 * if searched in java:comp/env if name dont start with "java:"
419 * @throws IllegalArgumentException JNDI name null or empty
420 * @throws NamingException ressource can be retrieved from JNDI directory
421 * @since 1.1
422 */
423 public void setMailSessionFromJNDI(String jndiName) throws NamingException
424 {
425 if (EmailUtils.isEmpty(jndiName))
426 {
427 throw new IllegalArgumentException("JNDI name missing");
428 }
429 Context ctx = null;
430 if (jndiName.startsWith("java:"))
431 {
432 ctx = new InitialContext();
433 }
434 else
435 {
436 ctx = (Context) new InitialContext().lookup("java:comp/env");
437
438 }
439 this.setMailSession((Session) ctx.lookup(jndiName));
440 }
441
442 /**
443 * Initialise a mailsession object
444 *
445 * @return A Session.
446 * @throws EmailException thrown when host name was not set.
447 * @since 1.0
448 */
449 public Session getMailSession() throws EmailException
450 {
451 if (this.session == null)
452 {
453 Properties properties = new Properties(System.getProperties());
454 properties.setProperty(MAIL_TRANSPORT_PROTOCOL, SMTP);
455
456 if (EmailUtils.isEmpty(this.hostName))
457 {
458 this.hostName = properties.getProperty(MAIL_HOST);
459 }
460
461 if (EmailUtils.isEmpty(this.hostName))
462 {
463 throw new EmailException(
464 "Cannot find valid hostname for mail session");
465 }
466
467 properties.setProperty(MAIL_PORT, smtpPort);
468 properties.setProperty(MAIL_HOST, hostName);
469 properties.setProperty(MAIL_DEBUG, String.valueOf(this.debug));
470
471 if (this.authenticator != null)
472 {
473 properties.setProperty(MAIL_TRANSPORT_TLS, tls ? "true" : "false");
474 properties.setProperty(MAIL_SMTP_AUTH, "true");
475 }
476
477 if (this.ssl)
478 {
479 properties.setProperty(MAIL_PORT, sslSmtpPort);
480 properties.setProperty(MAIL_SMTP_SOCKET_FACTORY_PORT, sslSmtpPort);
481 properties.setProperty(MAIL_SMTP_SOCKET_FACTORY_CLASS, "javax.net.ssl.SSLSocketFactory");
482 properties.setProperty(MAIL_SMTP_SOCKET_FACTORY_FALLBACK, "false");
483 }
484
485 if (this.bounceAddress != null)
486 {
487 properties.setProperty(MAIL_SMTP_FROM, this.bounceAddress);
488 }
489
490 // changed this (back) to getInstance due to security exceptions
491 // caused when testing using maven
492 this.session =
493 Session.getInstance(properties, this.authenticator);
494 }
495 return this.session;
496 }
497
498 /**
499 * Creates a InternetAddress.
500 *
501 * @param email An email address.
502 * @param name A name.
503 * @param charsetName The name of the charset to encode the name with.
504 * @return An internet address.
505 * @throws EmailException Thrown when the supplied address, name or charset were invalid.
506 */
507 private InternetAddress createInternetAddress(String email, String name, String charsetName)
508 throws EmailException
509 {
510 InternetAddress address = null;
511
512 try
513 {
514 address = new InternetAddress(email);
515
516 // check name input
517 if (EmailUtils.isEmpty(name))
518 {
519 name = email;
520 }
521
522 // check charset input.
523 if (EmailUtils.isEmpty(charsetName))
524 {
525 address.setPersonal(name);
526 }
527 else
528 {
529 // canonicalize the charset name and make sure
530 // the current platform supports it.
531 Charset set = Charset.forName(charsetName);
532 address.setPersonal(name, set.name());
533 }
534
535 // run sanity check on new InternetAddress object; if this fails
536 // it will throw AddressException.
537 address.validate();
538 }
539 catch (AddressException e)
540 {
541 throw new EmailException(e);
542 }
543 catch (UnsupportedEncodingException e)
544 {
545 throw new EmailException(e);
546 }
547 return address;
548 }
549
550
551 /**
552 * Set the FROM field of the email to use the specified address. The email
553 * address will also be used as the personal name. The name will be encoded
554 * using the Java platform's default charset (UTF-16) if it contains
555 * non-ASCII characters; otherwise, it is used as is.
556 *
557 * @param email A String.
558 * @return An Email.
559 * @throws EmailException Indicates an invalid email address.
560 * @since 1.0
561 */
562 public Email setFrom(String email)
563 throws EmailException
564 {
565 return setFrom(email, null);
566 }
567
568 /**
569 * Set the FROM field of the email to use the specified address and the
570 * specified personal name. The name will be encoded using the Java
571 * platform's default charset (UTF-16) if it contains non-ASCII
572 * characters; otherwise, it is used as is.
573 *
574 * @param email A String.
575 * @param name A String.
576 * @throws EmailException Indicates an invalid email address.
577 * @return An Email.
578 * @since 1.0
579 */
580 public Email setFrom(String email, String name)
581 throws EmailException
582 {
583 return setFrom(email, name, null);
584 }
585
586 /**
587 * Set the FROM field of the email to use the specified address, personal
588 * name, and charset encoding for the name.
589 *
590 * @param email A String.
591 * @param name A String.
592 * @param charset The charset to encode the name with.
593 * @throws EmailException Indicates an invalid email address or charset.
594 * @return An Email.
595 * @since 1.1
596 */
597 public Email setFrom(String email, String name, String charset)
598 throws EmailException
599 {
600 this.fromAddress = createInternetAddress(email, name, charset);
601 return this;
602 }
603
604 /**
605 * Add a recipient TO to the email. The email
606 * address will also be used as the personal name. The name will be encoded
607 * using the Java platform's default charset (UTF-16) if it contains
608 * non-ASCII characters; otherwise, it is used as is.
609 *
610 * @param email A String.
611 * @throws EmailException Indicates an invalid email address.
612 * @return An Email.
613 * @since 1.0
614 */
615 public Email addTo(String email)
616 throws EmailException
617 {
618 return addTo(email, null);
619 }
620
621 /**
622 * Add a recipient TO to the email using the specified address and the
623 * specified personal name. The name will be encoded using the Java
624 * platform's default charset (UTF-16) if it contains non-ASCII
625 * characters; otherwise, it is used as is.
626 *
627 * @param email A String.
628 * @param name A String.
629 * @throws EmailException Indicates an invalid email address.
630 * @return An Email.
631 * @since 1.0
632 */
633 public Email addTo(String email, String name)
634 throws EmailException
635 {
636 return addTo(email, name, null);
637 }
638
639 /**
640 * Add a recipient TO to the email using the specified address, personal
641 * name, and charset encoding for the name.
642 *
643 * @param email A String.
644 * @param name A String.
645 * @param charset The charset to encode the name with.
646 * @throws EmailException Indicates an invalid email address or charset.
647 * @return An Email.
648 * @since 1.1
649 */
650 public Email addTo(String email, String name, String charset)
651 throws EmailException
652 {
653 this.toList.add(createInternetAddress(email, name, charset));
654 return this;
655 }
656
657 /**
658 * Set a list of "TO" addresses. All elements in the specified
659 * <code>Collection</code> are expected to be of type
660 * <code>java.mail.internet.InternetAddress</code>.
661 *
662 * @param aCollection collection of <code>InternetAddress</code> objects.
663 * @throws EmailException Indicates an invalid email address.
664 * @return An Email.
665 * @see javax.mail.internet.InternetAddress
666 * @since 1.0
667 */
668 public Email setTo(Collection aCollection) throws EmailException
669 {
670 if (aCollection == null || aCollection.isEmpty())
671 {
672 throw new EmailException("Address List provided was invalid");
673 }
674
675 this.toList = new ArrayList(aCollection);
676 return this;
677 }
678
679 /**
680 * Add a recipient CC to the email. The email
681 * address will also be used as the personal name. The name will be encoded
682 * using the Java platform's default charset (UTF-16) if it contains
683 * non-ASCII characters; otherwise, it is used as is.
684 *
685 * @param email A String.
686 * @return An Email.
687 * @throws EmailException Indicates an invalid email address.
688 * @since 1.0
689 */
690 public Email addCc(String email)
691 throws EmailException
692 {
693 return this.addCc(email, null);
694 }
695
696 /**
697 * Add a recipient CC to the email using the specified address and the
698 * specified personal name. The name will be encoded using the Java
699 * platform's default charset (UTF-16) if it contains non-ASCII
700 * characters; otherwise, it is used as is.
701 *
702 * @param email A String.
703 * @param name A String.
704 * @throws EmailException Indicates an invalid email address.
705 * @return An Email.
706 * @since 1.0
707 */
708 public Email addCc(String email, String name)
709 throws EmailException
710 {
711 return addCc(email, name, null);
712 }
713
714 /**
715 * Add a recipient CC to the email using the specified address, personal
716 * name, and charset encoding for the name.
717 *
718 * @param email A String.
719 * @param name A String.
720 * @param charset The charset to encode the name with.
721 * @throws EmailException Indicates an invalid email address or charset.
722 * @return An Email.
723 * @since 1.1
724 */
725 public Email addCc(String email, String name, String charset)
726 throws EmailException
727 {
728 this.ccList.add(createInternetAddress(email, name, charset));
729 return this;
730 }
731
732 /**
733 * Set a list of "CC" addresses. All elements in the specified
734 * <code>Collection</code> are expected to be of type
735 * <code>java.mail.internet.InternetAddress</code>.
736 *
737 * @param aCollection collection of <code>InternetAddress</code> objects.
738 * @return An Email.
739 * @throws EmailException Indicates an invalid email address.
740 * @see javax.mail.internet.InternetAddress
741 * @since 1.0
742 */
743 public Email setCc(Collection aCollection) throws EmailException
744 {
745 if (aCollection == null || aCollection.isEmpty())
746 {
747 throw new EmailException("Address List provided was invalid");
748 }
749
750 this.ccList = new ArrayList(aCollection);
751 return this;
752 }
753
754 /**
755 * Add a blind BCC recipient to the email. The email
756 * address will also be used as the personal name. The name will be encoded
757 * using the Java platform's default charset (UTF-16) if it contains
758 * non-ASCII characters; otherwise, it is used as is.
759 *
760 * @param email A String.
761 * @return An Email.
762 * @throws EmailException Indicates an invalid email address
763 * @since 1.0
764 */
765 public Email addBcc(String email)
766 throws EmailException
767 {
768 return this.addBcc(email, null);
769 }
770
771 /**
772 * Add a blind BCC recipient to the email using the specified address and
773 * the specified personal name. The name will be encoded using the Java
774 * platform's default charset (UTF-16) if it contains non-ASCII
775 * characters; otherwise, it is used as is.
776 *
777 * @param email A String.
778 * @param name A String.
779 * @return An Email.
780 * @throws EmailException Indicates an invalid email address
781 * @since 1.0
782 */
783 public Email addBcc(String email, String name)
784 throws EmailException
785 {
786 return addBcc(email, name, null);
787 }
788
789 /**
790 * Add a blind BCC recipient to the email using the specified address,
791 * personal name, and charset encoding for the name.
792 *
793 * @param email A String.
794 * @param name A String.
795 * @param charset The charset to encode the name with.
796 * @return An Email.
797 * @throws EmailException Indicates an invalid email address
798 * @since 1.1
799 */
800 public Email addBcc(String email, String name, String charset)
801 throws EmailException
802 {
803 this.bccList.add(createInternetAddress(email, name, charset));
804 return this;
805 }
806
807 /**
808 * Set a list of "BCC" addresses. All elements in the specified
809 * <code>Collection</code> are expected to be of type
810 * <code>java.mail.internet.InternetAddress</code>.
811 *
812 * @param aCollection collection of <code>InternetAddress</code> objects
813 * @return An Email.
814 * @throws EmailException Indicates an invalid email address
815 * @see javax.mail.internet.InternetAddress
816 * @since 1.0
817 */
818 public Email setBcc(Collection aCollection) throws EmailException
819 {
820 if (aCollection == null || aCollection.isEmpty())
821 {
822 throw new EmailException("Address List provided was invalid");
823 }
824
825 this.bccList = new ArrayList(aCollection);
826 return this;
827 }
828
829 /**
830 * Add a reply to address to the email. The email
831 * address will also be used as the personal name. The name will be encoded
832 * using the Java platform's default charset (UTF-16) if it contains
833 * non-ASCII characters; otherwise, it is used as is.
834 *
835 * @param email A String.
836 * @return An Email.
837 * @throws EmailException Indicates an invalid email address
838 * @since 1.0
839 */
840 public Email addReplyTo(String email)
841 throws EmailException
842 {
843 return this.addReplyTo(email, null);
844 }
845
846 /**
847 * Add a reply to address to the email using the specified address and
848 * the specified personal name. The name will be encoded using the Java
849 * platform's default charset (UTF-16) if it contains non-ASCII
850 * characters; otherwise, it is used as is.
851 *
852 * @param email A String.
853 * @param name A String.
854 * @return An Email.
855 * @throws EmailException Indicates an invalid email address
856 * @since 1.0
857 */
858 public Email addReplyTo(String email, String name)
859 throws EmailException
860 {
861 return addReplyTo(email, name, null);
862 }
863
864 /**
865 * Add a reply to address to the email using the specified address,
866 * personal name, and charset encoding for the name.
867 *
868 * @param email A String.
869 * @param name A String.
870 * @param charset The charset to encode the name with.
871 * @return An Email.
872 * @throws EmailException Indicates an invalid email address or charset.
873 * @since 1.1
874 */
875 public Email addReplyTo(String email, String name, String charset)
876 throws EmailException
877 {
878 this.replyList.add(createInternetAddress(email, name, charset));
879 return this;
880 }
881
882 /**
883 * Set a list of reply to addresses. All elements in the specified
884 * <code>Collection</code> are expected to be of type
885 * <code>java.mail.internet.InternetAddress</code>.
886 *
887 * @param aCollection collection of <code>InternetAddress</code> objects
888 * @return An Email.
889 * @throws EmailException Indicates an invalid email address
890 * @see javax.mail.internet.InternetAddress
891 * @since 1.1
892 */
893 public Email setReplyTo(Collection aCollection) throws EmailException
894 {
895 if (aCollection == null || aCollection.isEmpty())
896 {
897 throw new EmailException("Address List provided was invalid");
898 }
899
900 this.replyList = new ArrayList(aCollection);
901 return this;
902 }
903
904 /**
905 * Used to specify the mail headers. Example:
906 *
907 * X-Mailer: Sendmail, X-Priority: 1( highest )
908 * or 2( high ) 3( normal ) 4( low ) and 5( lowest )
909 * Disposition-Notification-To: user@domain.net
910 *
911 * @param map A Map.
912 * @since 1.0
913 */
914 public void setHeaders(Map map)
915 {
916 Iterator iterKeyBad = map.entrySet().iterator();
917
918 while (iterKeyBad.hasNext())
919 {
920 Map.Entry entry = (Map.Entry) iterKeyBad.next();
921 String strName = (String) entry.getKey();
922 String strValue = (String) entry.getValue();
923
924 if (EmailUtils.isEmpty(strName))
925 {
926 throw new IllegalArgumentException("name can not be null");
927 }
928 if (EmailUtils.isEmpty(strValue))
929 {
930 throw new IllegalArgumentException("value can not be null");
931 }
932 }
933
934 // all is ok, update headers
935 this.headers = map;
936 }
937
938 /**
939 * Adds a header ( name, value ) to the headers Map.
940 *
941 * @param name A String with the name.
942 * @param value A String with the value.
943 * @since 1.0
944 */
945 public void addHeader(String name, String value)
946 {
947 if (EmailUtils.isEmpty(name))
948 {
949 throw new IllegalArgumentException("name can not be null");
950 }
951 if (EmailUtils.isEmpty(value))
952 {
953 throw new IllegalArgumentException("value can not be null");
954 }
955
956 this.headers.put(name, value);
957 }
958
959 /**
960 * Set the email subject.
961 *
962 * @param aSubject A String.
963 * @return An Email.
964 * @since 1.0
965 */
966 public Email setSubject(String aSubject)
967 {
968 this.subject = aSubject;
969 return this;
970 }
971
972 /**
973 * Set the "bounce address" - the address to which undeliverable messages
974 * will be returned. If this value is never set, then the message will be
975 * sent to the address specified with the System property "mail.smtp.from",
976 * or if that value is not set, then to the "from" address.
977 *
978 * @param email A String.
979 * @return An Email.
980 * @since 1.0
981 */
982 public Email setBounceAddress(String email)
983 {
984 this.bounceAddress = email;
985 return this;
986 }
987
988
989 /**
990 * Define the content of the mail. It should be overidden by the
991 * subclasses.
992 *
993 * @param msg A String.
994 * @return An Email.
995 * @throws EmailException generic exception.
996 * @since 1.0
997 */
998 public abstract Email setMsg(String msg) throws EmailException;
999
1000 /**
1001 * Build the internal MimeMessage to be sent.
1002 *
1003 * @throws EmailException if there was an error.
1004 * @since 1.0
1005 */
1006 public void buildMimeMessage() throws EmailException
1007 {
1008 try
1009 {
1010 this.getMailSession();
1011 this.message = new MimeMessage(this.session);
1012
1013 if (EmailUtils.isNotEmpty(this.subject))
1014 {
1015 if (EmailUtils.isNotEmpty(this.charset))
1016 {
1017 this.message.setSubject(this.subject, this.charset);
1018 }
1019 else
1020 {
1021 this.message.setSubject(this.subject);
1022 }
1023 }
1024
1025 // ========================================================
1026 // Start of replacement code
1027 if (this.content != null)
1028 {
1029 this.message.setContent(this.content, this.contentType);
1030 }
1031 // end of replacement code
1032 // ========================================================
1033 else if (this.emailBody != null)
1034 {
1035 this.message.setContent(this.emailBody);
1036 }
1037 else
1038 {
1039 this.message.setContent("", Email.TEXT_PLAIN);
1040 }
1041
1042 if (this.fromAddress != null)
1043 {
1044 this.message.setFrom(this.fromAddress);
1045 }
1046 else
1047 {
1048 if (session.getProperty(MAIL_SMTP_FROM) == null)
1049 {
1050 throw new EmailException("From address required");
1051 }
1052 }
1053
1054 if (this.toList.size() + this.ccList.size() + this.bccList.size() == 0)
1055 {
1056 throw new EmailException(
1057 "At least one receiver address required");
1058 }
1059
1060 if (this.toList.size() > 0)
1061 {
1062 this.message.setRecipients(
1063 Message.RecipientType.TO,
1064 this.toInternetAddressArray(this.toList));
1065 }
1066
1067 if (this.ccList.size() > 0)
1068 {
1069 this.message.setRecipients(
1070 Message.RecipientType.CC,
1071 this.toInternetAddressArray(this.ccList));
1072 }
1073
1074 if (this.bccList.size() > 0)
1075 {
1076 this.message.setRecipients(
1077 Message.RecipientType.BCC,
1078 this.toInternetAddressArray(this.bccList));
1079 }
1080
1081 if (this.replyList.size() > 0)
1082 {
1083 this.message.setReplyTo(
1084 this.toInternetAddressArray(this.replyList));
1085 }
1086
1087 if (this.headers.size() > 0)
1088 {
1089 Iterator iterHeaderKeys = this.headers.keySet().iterator();
1090 while (iterHeaderKeys.hasNext())
1091 {
1092 String name = (String) iterHeaderKeys.next();
1093 String value = (String) headers.get(name);
1094 this.message.addHeader(name, value);
1095 }
1096 }
1097
1098 if (this.message.getSentDate() == null)
1099 {
1100 this.message.setSentDate(getSentDate());
1101 }
1102
1103 if (this.popBeforeSmtp)
1104 {
1105 Store store = session.getStore("pop3");
1106 store.connect(this.popHost, this.popUsername, this.popPassword);
1107 }
1108 }
1109 catch (MessagingException me)
1110 {
1111 throw new EmailException(me);
1112 }
1113 }
1114
1115 /**
1116 * Sends the previously created MimeMessage to the SMTP server.
1117 *
1118 * @return the message id of the underlying MimeMessage
1119 * @throws EmailException the sending failed
1120 */
1121 public String sendMimeMessage()
1122 throws EmailException
1123 {
1124 EmailUtils.notNull(this.message, "message");
1125
1126 try
1127 {
1128 Transport.send(this.message);
1129 return this.message.getMessageID();
1130 }
1131 catch (Throwable t)
1132 {
1133 String msg = "Sending the email to the following server failed : "
1134 + this.getHostName()
1135 + ":"
1136 + this.getSmtpPort();
1137
1138 throw new EmailException(msg, t);
1139 }
1140 }
1141
1142 /**
1143 * Returns the internal MimeMessage. Please not that the
1144 * MimeMessage is build by the buildMimeMessage() method.
1145 *
1146 * @return the MimeMessage
1147 */
1148 public MimeMessage getMimeMessage()
1149 {
1150 return this.message;
1151 }
1152
1153 /**
1154 * Sends the email. Internally we build a MimeMessage
1155 * which is afterwards sent to the SMTP server.
1156 *
1157 * @return the message id of the underlying MimeMessage
1158 * @throws EmailException the sending failed
1159 */
1160 public String send() throws EmailException
1161 {
1162 this.buildMimeMessage();
1163 return this.sendMimeMessage();
1164 }
1165
1166 /**
1167 * Sets the sent date for the email. The sent date will default to the
1168 * current date if not explictly set.
1169 *
1170 * @param date Date to use as the sent date on the email
1171 * @since 1.0
1172 */
1173 public void setSentDate(Date date)
1174 {
1175 this.sentDate = date;
1176 }
1177
1178 /**
1179 * Gets the sent date for the email.
1180 *
1181 * @return date to be used as the sent date for the email
1182 * @since 1.0
1183 */
1184 public Date getSentDate()
1185 {
1186 if (this.sentDate == null)
1187 {
1188 return new Date();
1189 }
1190 return this.sentDate;
1191 }
1192
1193 /**
1194 * Gets the subject of the email.
1195 *
1196 * @return email subject
1197 */
1198 public String getSubject()
1199 {
1200 return this.subject;
1201 }
1202
1203 /**
1204 * Gets the sender of the email.
1205 *
1206 * @return from address
1207 */
1208 public InternetAddress getFromAddress()
1209 {
1210 return this.fromAddress;
1211 }
1212
1213 /**
1214 * Gets the host name of the SMTP server,
1215 *
1216 * @return host name
1217 */
1218 public String getHostName()
1219 {
1220 if (EmailUtils.isNotEmpty(this.hostName))
1221 {
1222 return this.hostName;
1223 }
1224 else
1225 {
1226 return this.session.getProperty(MAIL_HOST);
1227 }
1228 }
1229
1230 /**
1231 * Gets the listening port of the SMTP server.
1232 *
1233 * @return smtp port
1234 */
1235 public String getSmtpPort()
1236 {
1237 if (EmailUtils.isNotEmpty(this.smtpPort))
1238 {
1239 return this.smtpPort;
1240 }
1241 else
1242 {
1243 return this.session.getProperty(MAIL_PORT);
1244 }
1245 }
1246
1247 /**
1248 * Gets encryption mode for authentication
1249 *
1250 * @return true if using TLS for authentication, false otherwise
1251 * @since 1.1
1252 */
1253 public boolean isTLS()
1254 {
1255 return this.tls;
1256 }
1257
1258 /**
1259 * Utility to copy List of known InternetAddress objects into an
1260 * array.
1261 *
1262 * @param list A List.
1263 * @return An InternetAddress[].
1264 * @since 1.0
1265 */
1266 protected InternetAddress[] toInternetAddressArray(List list)
1267 {
1268 InternetAddress[] ia =
1269 (InternetAddress[]) list.toArray(new InternetAddress[list.size()]);
1270
1271 return ia;
1272 }
1273
1274 /**
1275 * Set details regarding "pop3 before smtp" authentication.
1276 *
1277 * @param newPopBeforeSmtp Wether or not to log into pop3
1278 * server before sending mail.
1279 * @param newPopHost The pop3 host to use.
1280 * @param newPopUsername The pop3 username.
1281 * @param newPopPassword The pop3 password.
1282 * @since 1.0
1283 */
1284 public void setPopBeforeSmtp(
1285 boolean newPopBeforeSmtp,
1286 String newPopHost,
1287 String newPopUsername,
1288 String newPopPassword)
1289 {
1290 this.popBeforeSmtp = newPopBeforeSmtp;
1291 this.popHost = newPopHost;
1292 this.popUsername = newPopUsername;
1293 this.popPassword = newPopPassword;
1294 }
1295
1296 /**
1297 * Returns whether SSL encryption for the transport is currently enabled.
1298 * @return true if SSL enabled for the transport
1299 */
1300 public boolean isSSL()
1301 {
1302 return ssl;
1303 }
1304
1305 /**
1306 * Sets whether SSL encryption should be enabled for the SMTP transport.
1307 * @param ssl whether to enable the SSL transport
1308 */
1309 public void setSSL(boolean ssl)
1310 {
1311 this.ssl = ssl;
1312 }
1313
1314 /**
1315 * Returns the current SSL port used by the SMTP transport.
1316 * @return the current SSL port used by the SMTP transport
1317 */
1318 public String getSslSmtpPort()
1319 {
1320 if (EmailUtils.isNotEmpty(this.sslSmtpPort))
1321 {
1322 return this.sslSmtpPort;
1323 }
1324 else
1325 {
1326 return this.session.getProperty(MAIL_SMTP_SOCKET_FACTORY_PORT);
1327 }
1328 }
1329
1330 /**
1331 * Sets the SSL port to use for the SMTP transport. Defaults to the standard
1332 * port, 465.
1333 * @param sslSmtpPort the SSL port to use for the SMTP transport
1334 */
1335 public void setSslSmtpPort(String sslSmtpPort)
1336 {
1337 this.sslSmtpPort = sslSmtpPort;
1338 }
1339 }