View Javadoc

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.mail;
18  
19  import java.io.File;
20  import java.io.IOException;
21  import java.io.InputStream;
22  import java.net.URL;
23  
24  import javax.activation.DataHandler;
25  import javax.activation.DataSource;
26  import javax.activation.FileDataSource;
27  import javax.activation.URLDataSource;
28  import javax.mail.BodyPart;
29  import javax.mail.MessagingException;
30  import javax.mail.internet.MimeBodyPart;
31  import javax.mail.internet.MimeMultipart;
32  import javax.mail.internet.MimePart;
33  
34  /**
35   * A multipart email.
36   *
37   * <p>This class is used to send multi-part internet email like
38   * messages with attachments.
39   *
40   * <p>To create a multi-part email, call the default constructor and
41   * then you can call setMsg() to set the message and call the
42   * different attach() methods.
43   *
44   * @since 1.0
45   * @author <a href="mailto:quintonm@bellsouth.net">Quinton McCombs</a>
46   * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a>
47   * @author <a href="mailto:frank.kim@clearink.com">Frank Y. Kim</a>
48   * @author <a href="mailto:bmclaugh@algx.net">Brett McLaughlin</a>
49   * @author <a href="mailto:unknown">Regis Koenig</a>
50   * @author <a href="mailto:corey.scott@gmail.com">Corey Scott</a>
51   * @version $Id: MultiPartEmail.java 577479 2007-09-20 00:01:18Z bspeakmon $
52   */
53  public class MultiPartEmail extends Email
54  {
55      /** Body portion of the email. */
56      private MimeMultipart container;
57  
58      /** The message container. */
59      private BodyPart primaryBodyPart;
60  
61      /** The MIME subtype. */
62      private String subType;
63  
64      /** Indicates if the message has been initialized */
65      private boolean initialized;
66  
67      /** Indicates if attachments have been added to the message */
68      private boolean boolHasAttachments;
69  
70      /**
71       * Set the MIME subtype of the email.
72       *
73       * @param aSubType MIME subtype of the email
74       * @since 1.0
75       */
76      public void setSubType(String aSubType)
77      {
78          this.subType = aSubType;
79      }
80  
81      /**
82       * Get the MIME subtype of the email.
83       *
84       * @return MIME subtype of the email
85       * @since 1.0
86       */
87      public String getSubType()
88      {
89          return subType;
90      }
91  
92      /**
93       * Add a new part to the email.
94       *
95       * @param partContent The content.
96       * @param partContentType The content type.
97       * @return An Email.
98       * @throws EmailException see javax.mail.internet.MimeBodyPart
99       *  for definitions
100      * @since 1.0
101      */
102     public Email addPart(String partContent, String partContentType)
103         throws EmailException
104     {
105             BodyPart bodyPart = createBodyPart();
106         try
107         {
108             bodyPart.setContent(partContent, partContentType);
109             getContainer().addBodyPart(bodyPart);
110         }
111         catch (MessagingException me)
112         {
113             throw new EmailException(me);
114         }
115 
116         return this;
117     }
118 
119     /**
120      * Add a new part to the email.
121      *
122      * @param multipart The MimeMultipart.
123      * @return An Email.
124      * @throws EmailException see javax.mail.internet.MimeBodyPart
125      *  for definitions
126      *  @since 1.0
127      */
128     public Email addPart(MimeMultipart multipart) throws EmailException
129     {
130         try
131         {
132             return addPart(multipart, getContainer().getCount());
133         }
134         catch (MessagingException me)
135         {
136             throw new EmailException(me);
137         }
138     }
139 
140     /**
141      * Add a new part to the email.
142      *
143      * @param multipart The part to add.
144      * @param index The index to add at.
145      * @return The email.
146      * @throws EmailException An error occured while adding the part.
147      * @since 1.0
148      */
149     public Email addPart(MimeMultipart multipart, int index) throws EmailException
150     {
151             BodyPart bodyPart = createBodyPart();
152         try
153         {
154             bodyPart.setContent(multipart);
155             getContainer().addBodyPart(bodyPart, index);
156         }
157         catch (MessagingException me)
158         {
159             throw new EmailException(me);
160         }
161 
162         return this;
163     }
164 
165     /**
166      * Initialize the multipart email.
167      * @since 1.0
168      */
169     protected void init()
170     {
171         if (initialized)
172         {
173             throw new IllegalStateException("Already initialized");
174         }
175 
176         container = createMimeMultipart();
177         super.setContent(container);
178 
179         initialized = true;
180     }
181 
182     /**
183      * Set the message of the email.
184      *
185      * @param msg A String.
186      * @return An Email.
187      * @throws EmailException see javax.mail.internet.MimeBodyPart
188      *  for definitions
189      * @since 1.0
190      */
191     public Email setMsg(String msg) throws EmailException
192     {
193         // throw exception on null message
194         if (EmailUtils.isEmpty(msg))
195         {
196             throw new EmailException("Invalid message supplied");
197         }
198         try
199         {
200             BodyPart primary = getPrimaryBodyPart();
201 
202             if ((primary instanceof MimePart) && EmailUtils.isNotEmpty(charset))
203             {
204                 ((MimePart) primary).setText(msg, charset);
205             }
206             else
207             {
208                 primary.setText(msg);
209             }
210         }
211         catch (MessagingException me)
212         {
213             throw new EmailException(me);
214         }
215         return this;
216     }
217 
218     /**
219      * Builds the actual MimeMessage
220      *
221      * @throws EmailException see javax.mail.internet.MimeBodyPart
222      *  for definitions
223      * @since 1.0
224      */
225     public void buildMimeMessage() throws EmailException
226     {
227         try
228         {
229             if (primaryBodyPart != null)
230             {
231                 // before a multipart message can be sent, we must make sure that
232                 // the content for the main body part was actually set.  If not,
233                 // an IOException will be thrown during super.send().
234 
235                 BodyPart body = this.getPrimaryBodyPart();
236                 try
237                 {
238                     body.getContent();
239                 }
240                 catch (IOException e)
241                 {
242                     // do nothing here.  content will be set to an empty string
243                     // as a result.
244                     // (Should this really be rethrown as an email exception?)
245                     // throw new EmailException(e);
246                 }
247             }
248 
249             if (subType != null)
250             {
251                 getContainer().setSubType(subType);
252             }
253 
254             super.buildMimeMessage();
255         }
256         catch (MessagingException me)
257         {
258             throw new EmailException(me);
259         }
260     }
261 
262     /**
263      * Attach an EmailAttachment.
264      *
265      * @param attachment An EmailAttachment.
266      * @return A MultiPartEmail.
267      * @throws EmailException see javax.mail.internet.MimeBodyPart
268      *  for definitions
269      * @since 1.0
270      */
271     public MultiPartEmail attach(EmailAttachment attachment)
272         throws EmailException
273     {
274         MultiPartEmail result = null;
275 
276         if (attachment == null)
277         {
278             throw new EmailException("Invalid attachment supplied");
279         }
280 
281         URL url = attachment.getURL();
282 
283         if (url == null)
284         {
285             String fileName = null;
286             try
287             {
288                 fileName = attachment.getPath();
289                 File file = new File(fileName);
290                 if (!file.exists())
291                 {
292                     throw new IOException(
293                         "\"" + fileName + "\" does not exist");
294                 }
295                 result =
296                     attach(
297                         new FileDataSource(file),
298                         attachment.getName(),
299                         attachment.getDescription(),
300                         attachment.getDisposition());
301             }
302             catch (IOException e)
303             {
304                 throw new EmailException(
305                     "Cannot attach file \"" + fileName + "\"",
306                     e);
307             }
308         }
309         else
310         {
311             result =
312                 attach(
313                     url,
314                     attachment.getName(),
315                     attachment.getDescription(),
316                     attachment.getDisposition());
317         }
318 
319         return result;
320     }
321 
322     /**
323      * Attach a file located by its URL.  The disposition of the file
324      * is set to mixed.
325      *
326      * @param url The URL of the file (may be any valid URL).
327      * @param name The name field for the attachment.
328      * @param description A description for the attachment.
329      * @return A MultiPartEmail.
330      * @throws EmailException see javax.mail.internet.MimeBodyPart
331      *  for definitions
332      * @since 1.0
333      */
334     public MultiPartEmail attach(URL url, String name, String description)
335         throws EmailException
336     {
337         return attach(url, name, description, EmailAttachment.ATTACHMENT);
338     }
339 
340     /**
341      * Attach a file located by its URL.
342      *
343      * @param url The URL of the file (may be any valid URL).
344      * @param name The name field for the attachment.
345      * @param description A description for the attachment.
346      * @param disposition Either mixed or inline.
347      * @return A MultiPartEmail.
348      * @throws EmailException see javax.mail.internet.MimeBodyPart
349      *  for definitions
350      * @since 1.0
351      */
352     public MultiPartEmail attach(
353         URL url,
354         String name,
355         String description,
356         String disposition)
357         throws EmailException
358     {
359         // verify that the URL is valid
360        try
361        {
362            InputStream is = url.openStream();
363            is.close();
364        }
365        catch (IOException e)
366        {
367            throw new EmailException("Invalid URL set");
368        }
369 
370        return attach(new URLDataSource(url), name, description, disposition);
371     }
372 
373     /**
374      * Attach a file specified as a DataSource interface.
375      *
376      * @param ds A DataSource interface for the file.
377      * @param name The name field for the attachment.
378      * @param description A description for the attachment.
379      * @return A MultiPartEmail.
380      * @throws EmailException see javax.mail.internet.MimeBodyPart
381      *  for definitions
382      * @since 1.0
383      */
384     public MultiPartEmail attach(
385         DataSource ds,
386         String name,
387         String description)
388         throws EmailException
389     {
390         // verify that the DataSource is valid
391         try
392         {
393             if (ds == null || ds.getInputStream() == null)
394             {
395                 throw new EmailException("Invalid Datasource");
396             }
397         }
398         catch (IOException e)
399         {
400             throw new EmailException("Invalid Datasource");
401         }
402 
403         return attach(ds, name, description, EmailAttachment.ATTACHMENT);
404     }
405 
406     /**
407      * Attach a file specified as a DataSource interface.
408      *
409      * @param ds A DataSource interface for the file.
410      * @param name The name field for the attachment.
411      * @param description A description for the attachment.
412      * @param disposition Either mixed or inline.
413      * @return A MultiPartEmail.
414      * @throws EmailException see javax.mail.internet.MimeBodyPart
415      *  for definitions
416      * @since 1.0
417      */
418     public MultiPartEmail attach(
419         DataSource ds,
420         String name,
421         String description,
422         String disposition)
423         throws EmailException
424     {
425         if (EmailUtils.isEmpty(name))
426         {
427             name = ds.getName();
428         }
429         BodyPart bodyPart = createBodyPart();
430         try
431         {
432             getContainer().addBodyPart(bodyPart);
433 
434             bodyPart.setDisposition(disposition);
435             bodyPart.setFileName(name);
436             bodyPart.setDescription(description);
437             bodyPart.setDataHandler(new DataHandler(ds));
438         }
439         catch (MessagingException me)
440         {
441             throw new EmailException(me);
442         }
443         setBoolHasAttachments(true);
444 
445         return this;
446     }
447 
448     /**
449      * Gets first body part of the message.
450      *
451      * @return The primary body part.
452      * @throws MessagingException An error occured while getting the primary body part.
453      * @since 1.0
454      */
455     protected BodyPart getPrimaryBodyPart() throws MessagingException
456     {
457         if (!initialized)
458         {
459             init();
460         }
461 
462         // Add the first body part to the message.  The fist body part must be
463         if (this.primaryBodyPart == null)
464         {
465             primaryBodyPart = createBodyPart();
466             getContainer().addBodyPart(primaryBodyPart, 0);
467         }
468 
469         return primaryBodyPart;
470     }
471 
472     /**
473      * Gets the message container.
474      *
475      * @return The message container.
476      * @since 1.0
477      */
478     protected MimeMultipart getContainer()
479     {
480         if (!initialized)
481         {
482             init();
483         }
484         return container;
485     }
486 
487     /**
488      * Creates a body part object.
489      * Can be overridden if you don't want to create a BodyPart.
490      *
491      * @return the created body part
492      */
493     protected BodyPart createBodyPart()
494     {
495         BodyPart bodyPart = new MimeBodyPart();
496         return bodyPart;
497     }
498     /**
499      * Creates a mime multipart object.
500      *
501      * @return the created mime part
502      */
503     protected MimeMultipart createMimeMultipart()
504     {
505         MimeMultipart mmp = new MimeMultipart();
506         return mmp;
507     }
508 
509     /**
510      * Checks whether there are attachments.
511      *
512      * @return true if there are attachments
513      * @since 1.0
514      */
515     public boolean isBoolHasAttachments()
516     {
517         return boolHasAttachments;
518     }
519 
520     /**
521      * Sets whether there are attachments.
522      *
523      * @param b  the attachments flag
524      * @since 1.0
525      */
526     public void setBoolHasAttachments(boolean b)
527     {
528         boolHasAttachments = b;
529     }
530 
531     /**
532      * Checks if this object is initialized.
533      *
534      * @return true if initialized
535      */
536     protected boolean isInitialized()
537     {
538         return initialized;
539     }
540 
541     /**
542      * Sets the initialized status of this object.
543      *
544      * @param b  the initialized status flag
545      */
546     protected void setInitialized(boolean b)
547     {
548         initialized = b;
549     }
550 
551 }