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.IOException;
19  import java.io.InputStream;
20  import java.net.URL;
21  import java.util.ArrayList;
22  import java.util.Iterator;
23  import java.util.List;
24  
25  import javax.activation.DataHandler;
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  
32  /**
33   * An HTML multipart email.
34   *
35   * <p>This class is used to send HTML formatted email.  A text message
36   * can also be set for HTML unaware email clients, such as text-based
37   * email clients.
38   *
39   * <p>This class also inherits from MultiPartEmail, so it is easy to
40   * add attachments to the email.
41   *
42   * <p>To send an email in HTML, one should create a HtmlEmail, then
43   * use the setFrom, addTo, etc. methods.  The HTML content can be set
44   * with the setHtmlMsg method.  The alternative text content can be set
45   * with setTextMsg.
46   *
47   * <p>Either the text or HTML can be omitted, in which case the "main"
48   * part of the multipart becomes whichever is supplied rather than a
49   * multipart/alternative.
50   *
51   * @since 1.0
52   * @author <a href="mailto:unknown">Regis Koenig</a>
53   * @author <a href="mailto:sean@informage.net">Sean Legassick</a>
54   * @version $Id: HtmlEmail.java 279285 2005-09-07 09:52:44Z henning $
55   */
56  public class HtmlEmail extends MultiPartEmail
57  {
58      /** Definition of the length of generated CID's */
59      public static final int CID_LENGTH = 10;
60  
61      /**
62       * Text part of the message.  This will be used as alternative text if
63       * the email client does not support HTML messages.
64       */
65      protected String text;
66  
67      /** Html part of the message */
68      protected String html;
69  
70      /** Embedded images */
71      protected List inlineImages = new ArrayList();
72  
73      /**
74       * Set the text content.
75       *
76       * @param aText A String.
77       * @return An HtmlEmail.
78       * @throws EmailException see javax.mail.internet.MimeBodyPart
79       *  for definitions
80       * @since 1.0
81       */
82      public HtmlEmail setTextMsg(String aText) throws EmailException
83      {
84          if (EmailUtils.isEmpty(aText))
85          {
86              throw new EmailException("Invalid message supplied");
87          }
88  
89         this.text = aText;
90          return this;
91      }
92  
93      /**
94       * Set the HTML content.
95       *
96       * @param aHtml A String.
97       * @return An HtmlEmail.
98       * @throws EmailException see javax.mail.internet.MimeBodyPart
99       *  for definitions
100      * @since 1.0
101      */
102     public HtmlEmail setHtmlMsg(String aHtml) throws EmailException
103     {
104         if (EmailUtils.isEmpty(aHtml))
105         {
106             throw new EmailException("Invalid message supplied");
107         }
108 
109         this.html = aHtml;
110         return this;
111     }
112 
113     /**
114      * Set the message.
115      *
116      * <p>This method overrides the MultiPartEmail setMsg() method in
117      * order to send an HTML message instead of a full text message in
118      * the mail body. The message is formatted in HTML for the HTML
119      * part of the message, it is let as is in the alternate text
120      * part.
121      *
122      * @param msg A String.
123      * @return An Email.
124      * @throws EmailException see javax.mail.internet.MimeBodyPart
125      *  for definitions
126      * @since 1.0
127      */
128     public Email setMsg(String msg) throws EmailException
129     {
130         if (EmailUtils.isEmpty(msg))
131         {
132             throw new EmailException("Invalid message supplied");
133         }
134 
135         setTextMsg(msg);
136 
137         setHtmlMsg(
138             new StringBuffer()
139                 .append("<html><body><pre>")
140                 .append(msg)
141                 .append("</pre></body></html>")
142                 .toString());
143 
144         return this;
145     }
146 
147     /**
148      * Embeds an URL in the HTML.
149      *
150      * <p>This method allows to embed a file located by an URL into
151      * the mail body.  It allows, for instance, to add inline images
152      * to the email.  Inline files may be referenced with a
153      * <code>cid:xxxxxx</code> URL, where xxxxxx is the Content-ID
154      * returned by the embed function.
155      *
156      * <p>Example of use:<br><code><pre>
157      * HtmlEmail he = new HtmlEmail();
158      * he.setHtmlMsg("&lt;html&gt;&lt;img src=cid:" +
159      *  embed("file:/my/image.gif","image.gif") +
160      *  "&gt;&lt;/html&gt;");
161      * // code to set the others email fields (not shown)
162      * </pre></code>
163      *
164      * @param url The URL of the file.
165      * @param name The name that will be set in the filename header
166      * field.
167      * @return A String with the Content-ID of the file.
168      * @throws EmailException when URL supplied is invalid
169      *  also see javax.mail.internet.MimeBodyPart for definitions
170      * @since 1.0
171      */
172     public String embed(URL url, String name) throws EmailException
173     {
174         // verify that the URL is valid
175         try
176         {
177             InputStream is = url.openStream();
178             is.close();
179         }
180         catch (IOException e)
181         {
182             throw new EmailException("Invalid URL");
183         }
184 
185         MimeBodyPart mbp = new MimeBodyPart();
186 
187         try
188         {
189             mbp.setDataHandler(new DataHandler(new URLDataSource(url)));
190             mbp.setFileName(name);
191             mbp.setDisposition("inline");
192             String cid = EmailUtils.randomAlphabetic(HtmlEmail.CID_LENGTH).toLowerCase();
193             mbp.addHeader("Content-ID", "<" + cid + ">");
194             this.inlineImages.add(mbp);
195             return cid;
196         }
197         catch (MessagingException me)
198         {
199             throw new EmailException(me);
200         }
201     }
202 
203     /**
204      * Does the work of actually building the email.
205      *
206      * @exception EmailException if there was an error.
207      * @since 1.0
208      */
209     public void buildMimeMessage() throws EmailException
210     {
211         try
212         {
213             // if the email has attachments then the base type is mixed,
214             // otherwise it should be related
215             if (this.isBoolHasAttachments())
216             {
217                 this.buildAttachments();
218             }
219             else
220             {
221                 this.buildNoAttachments();
222             }
223 
224         }
225         catch (MessagingException me)
226         {
227             throw new EmailException(me);
228         }
229         super.buildMimeMessage();
230     }
231 
232     /**
233      * @throws EmailException EmailException
234      * @throws MessagingException MessagingException
235      */
236     private void buildAttachments() throws MessagingException, EmailException
237     {
238         MimeMultipart container = this.getContainer();
239         MimeMultipart subContainer = null;
240         MimeMultipart subContainerHTML = new MimeMultipart("related");
241         BodyPart msgHtml = null;
242         BodyPart msgText = null;
243 
244         container.setSubType("mixed");
245         subContainer = new MimeMultipart("alternative");
246 
247         if (EmailUtils.isNotEmpty(this.text))
248         {
249             msgText = new MimeBodyPart();
250             subContainer.addBodyPart(msgText);
251 
252             if (EmailUtils.isNotEmpty(this.charset))
253             {
254                 msgText.setContent(
255                     this.text,
256                     Email.TEXT_PLAIN + "; charset=" + this.charset);
257             }
258             else
259             {
260                 msgText.setContent(this.text, Email.TEXT_PLAIN);
261             }
262         }
263 
264         if (EmailUtils.isNotEmpty(this.html))
265         {
266             if (this.inlineImages.size() > 0)
267             {
268                 msgHtml = new MimeBodyPart();
269                 subContainerHTML.addBodyPart(msgHtml);
270             }
271             else
272             {
273                 msgHtml = new MimeBodyPart();
274                 subContainer.addBodyPart(msgHtml);
275             }
276 
277             if (EmailUtils.isNotEmpty(this.charset))
278             {
279                 msgHtml.setContent(
280                     this.html,
281                     Email.TEXT_HTML + "; charset=" + this.charset);
282             }
283             else
284             {
285                 msgHtml.setContent(this.html, Email.TEXT_HTML);
286             }
287 
288             Iterator iter = this.inlineImages.iterator();
289             while (iter.hasNext())
290             {
291                 subContainerHTML.addBodyPart((BodyPart) iter.next());
292             }
293         }
294 
295         // add sub containers to message
296         this.addPart(subContainer, 0);
297 
298         if (this.inlineImages.size() > 0)
299         {
300             // add sub container to message
301             this.addPart(subContainerHTML, 1);
302         }
303     }
304 
305     /**
306      * @throws EmailException EmailException
307      * @throws MessagingException MessagingException
308      */
309     private void buildNoAttachments() throws MessagingException, EmailException
310     {
311         MimeMultipart container = this.getContainer();
312         MimeMultipart subContainerHTML = new MimeMultipart("related");
313 
314         container.setSubType("alternative");
315 
316         BodyPart msgText = null;
317         BodyPart msgHtml = null;
318 
319         if (EmailUtils.isNotEmpty(this.text))
320         {
321             msgText = this.getPrimaryBodyPart();
322             if (EmailUtils.isNotEmpty(this.charset))
323             {
324                 msgText.setContent(
325                     this.text,
326                     Email.TEXT_PLAIN + "; charset=" + this.charset);
327             }
328             else
329             {
330                 msgText.setContent(this.text, Email.TEXT_PLAIN);
331             }
332         }
333 
334         if (EmailUtils.isNotEmpty(this.html))
335         {
336             // if the txt part of the message was null, then the html part
337             // will become the primary body part
338             if (msgText == null)
339             {
340                 msgHtml = getPrimaryBodyPart();
341             }
342             else
343             {
344                 if (this.inlineImages.size() > 0)
345                 {
346                     msgHtml = new MimeBodyPart();
347                     subContainerHTML.addBodyPart(msgHtml);
348                 }
349                 else
350                 {
351                     msgHtml = new MimeBodyPart();
352                     container.addBodyPart(msgHtml, 1);
353                 }
354             }
355 
356             if (EmailUtils.isNotEmpty(this.charset))
357             {
358                 msgHtml.setContent(
359                     this.html,
360                     Email.TEXT_HTML + "; charset=" + this.charset);
361             }
362             else
363             {
364                 msgHtml.setContent(this.html, Email.TEXT_HTML);
365             }
366 
367             Iterator iter = this.inlineImages.iterator();
368             while (iter.hasNext())
369             {
370                 subContainerHTML.addBodyPart((BodyPart) iter.next());
371             }
372 
373             if (this.inlineImages.size() > 0)
374             {
375                 // add sub container to message
376                 this.addPart(subContainerHTML);
377             }
378         }
379     }
380 }