View Javadoc

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