001 package railo.runtime.net.mail; 002 003 import java.io.IOException; 004 import java.io.InputStream; 005 import java.net.URL; 006 import java.util.ArrayList; 007 import java.util.Iterator; 008 import java.util.List; 009 010 import javax.activation.DataHandler; 011 import javax.activation.URLDataSource; 012 import javax.mail.BodyPart; 013 import javax.mail.MessagingException; 014 import javax.mail.internet.MimeBodyPart; 015 import javax.mail.internet.MimeMultipart; 016 017 import org.apache.commons.mail.Email; 018 import org.apache.commons.mail.EmailException; 019 import org.apache.commons.mail.MultiPartEmail; 020 021 import railo.commons.lang.StringUtil; 022 023 /** 024 * An HTML multipart email. 025 * 026 * <p>This class is used to send HTML formatted email. A text message 027 * can also be set for HTML unaware email clients, such as text-based 028 * email clients. 029 * 030 * <p>This class also inherits from MultiPartEmail, so it is easy to 031 * add attachments to the email. 032 * 033 * <p>To send an email in HTML, one should create a HtmlEmail, then 034 * use the setFrom, addTo, etc. methods. The HTML content can be set 035 * with the setHtmlMsg method. The alternative text content can be set 036 * with setTextMsg. 037 * 038 * <p>Either the text or HTML can be omitted, in which case the "main" 039 * part of the multipart becomes whichever is supplied rather than a 040 * multipart/alternative. 041 * 042 * 043 */ 044 public final class HtmlEmailImpl extends MultiPartEmail 045 { 046 /** Definition of the length of generated CID's */ 047 public static final int CID_LENGTH = 10; 048 049 /** 050 * Text part of the message. This will be used as alternative text if 051 * the email client does not support HTML messages. 052 */ 053 protected String text; 054 055 /** Html part of the message */ 056 protected String html; 057 058 /** Embedded images */ 059 protected List inlineImages = new ArrayList(); 060 061 /** 062 * Set the text content. 063 * 064 * @param aText A String. 065 * @return An HtmlEmail. 066 * @throws EmailException see javax.mail.internet.MimeBodyPart 067 * for definitions 068 * 069 */ 070 public HtmlEmailImpl setTextMsg(String aText) throws EmailException { 071 if (StringUtil.isEmpty(aText)) { 072 throw new EmailException("Invalid message supplied"); 073 } 074 this.text = aText; 075 return this; 076 } 077 078 /** 079 * Set the HTML content. 080 * 081 * @param aHtml A String. 082 * @return An HtmlEmail. 083 * @throws EmailException see javax.mail.internet.MimeBodyPart 084 * for definitions 085 * 086 */ 087 public HtmlEmailImpl setHtmlMsg(String aHtml) throws EmailException { 088 if (StringUtil.isEmpty(aHtml)) { 089 throw new EmailException("Invalid message supplied"); 090 } 091 this.html = aHtml; 092 return this; 093 } 094 095 /** 096 * Set the message. 097 * 098 * <p>This method overrides the MultiPartEmail setMsg() method in 099 * order to send an HTML message instead of a full text message in 100 * the mail body. The message is formatted in HTML for the HTML 101 * part of the message, it is let as is in the alternate text 102 * part. 103 * 104 * @param msg A String. 105 * @return An Email. 106 * @throws EmailException see javax.mail.internet.MimeBodyPart 107 * for definitions 108 * 109 */ 110 public Email setMsg(String msg) throws EmailException { 111 if (StringUtil.isEmpty(msg)) { 112 throw new EmailException("Invalid message supplied"); 113 } 114 115 setTextMsg(msg); 116 117 setHtmlMsg( 118 new StringBuffer() 119 .append("<html><body><pre>") 120 .append(msg) 121 .append("</pre></body></html>") 122 .toString()); 123 124 return this; 125 } 126 127 /** 128 * Embeds an URL in the HTML. 129 * 130 * <p>This method allows to embed a file located by an URL into 131 * the mail body. It allows, for instance, to add inline images 132 * to the email. Inline files may be referenced with a 133 * <code>cid:xxxxxx</code> URL, where xxxxxx is the Content-ID 134 * returned by the embed function. 135 * 136 * <p>Example of use:<br><code><pre> 137 * HtmlEmail he = new HtmlEmail(); 138 * he.setHtmlMsg("<html><img src=cid:" + 139 * embed("file:/my/image.gif","image.gif") + 140 * "></html>"); 141 * // code to set the others email fields (not shown) 142 * </pre></code> 143 * 144 * @param url The URL of the file. 145 * @param cid A String with the Content-ID of the file. 146 * @param name The name that will be set in the filename header 147 * field. 148 * @throws EmailException when URL supplied is invalid 149 * also see javax.mail.internet.MimeBodyPart for definitions 150 * 151 */ 152 public void embed(URL url, String cid, String name) throws EmailException { 153 // verify that the URL is valid 154 try { 155 InputStream is = url.openStream(); 156 is.close(); 157 } 158 catch (IOException e) { 159 throw new EmailException("Invalid URL"); 160 } 161 162 MimeBodyPart mbp = new MimeBodyPart(); 163 164 try { 165 mbp.setDataHandler(new DataHandler(new URLDataSource(url))); 166 mbp.setFileName(name); 167 mbp.setDisposition("inline"); 168 mbp.addHeader("Content-ID", "<" + cid + ">"); 169 this.inlineImages.add(mbp); 170 } 171 catch (MessagingException me) { 172 throw new EmailException(me); 173 } 174 } 175 176 /** 177 * Does the work of actually building the email. 178 * 179 * @exception EmailException if there was an error. 180 * 181 */ 182 public void buildMimeMessage() throws EmailException { 183 try { 184 // if the email has attachments then the base type is mixed, 185 // otherwise it should be related 186 if (this.isBoolHasAttachments()) { 187 this.buildAttachments(); 188 } 189 else { 190 this.buildNoAttachments(); 191 } 192 193 } 194 catch (MessagingException me) 195 { 196 throw new EmailException(me); 197 } 198 super.buildMimeMessage(); 199 } 200 201 /** 202 * @throws EmailException EmailException 203 * @throws MessagingException MessagingException 204 */ 205 private void buildAttachments() throws MessagingException, EmailException 206 { 207 MimeMultipart container = this.getContainer(); 208 MimeMultipart subContainer = null; 209 MimeMultipart subContainerHTML = new MimeMultipart("related"); 210 BodyPart msgHtml = null; 211 BodyPart msgText = null; 212 213 container.setSubType("mixed"); 214 subContainer = new MimeMultipart("alternative"); 215 216 if (!StringUtil.isEmpty(this.text)) { 217 msgText = new MimeBodyPart(); 218 subContainer.addBodyPart(msgText); 219 220 if (!StringUtil.isEmpty(this.charset)) { 221 msgText.setContent( 222 this.text, 223 Email.TEXT_PLAIN + "; charset=" + this.charset); 224 } 225 else { 226 msgText.setContent(this.text, Email.TEXT_PLAIN); 227 } 228 } 229 230 if (!StringUtil.isEmpty(this.html)) 231 { 232 if (this.inlineImages.size() > 0) 233 { 234 msgHtml = new MimeBodyPart(); 235 subContainerHTML.addBodyPart(msgHtml); 236 } 237 else 238 { 239 msgHtml = new MimeBodyPart(); 240 subContainer.addBodyPart(msgHtml); 241 } 242 243 if (!StringUtil.isEmpty(this.charset)) 244 { 245 msgHtml.setContent( 246 this.html, 247 Email.TEXT_HTML + "; charset=" + this.charset); 248 } 249 else 250 { 251 msgHtml.setContent(this.html, Email.TEXT_HTML); 252 } 253 254 Iterator iter = this.inlineImages.iterator(); 255 while (iter.hasNext()) 256 { 257 subContainerHTML.addBodyPart((BodyPart) iter.next()); 258 } 259 } 260 261 // add sub containers to message 262 this.addPart(subContainer, 0); 263 264 if (this.inlineImages.size() > 0) 265 { 266 // add sub container to message 267 this.addPart(subContainerHTML, 1); 268 } 269 } 270 271 /** 272 * @throws EmailException EmailException 273 * @throws MessagingException MessagingException 274 */ 275 private void buildNoAttachments() throws MessagingException, EmailException 276 { 277 MimeMultipart container = this.getContainer(); 278 MimeMultipart subContainerHTML = new MimeMultipart("related"); 279 280 container.setSubType("alternative"); 281 282 BodyPart msgText = null; 283 BodyPart msgHtml = null; 284 285 if(!StringUtil.isEmpty(this.text)) { 286 msgText = this.getPrimaryBodyPart(); 287 if (!StringUtil.isEmpty(this.charset)) { 288 msgText.setContent( 289 this.text, 290 Email.TEXT_PLAIN + "; charset=" + this.charset); 291 } 292 else { 293 msgText.setContent(this.text, Email.TEXT_PLAIN); 294 } 295 } 296 297 if(!StringUtil.isEmpty(this.html)) { 298 // if the txt part of the message was null, then the html part 299 // will become the primary body part 300 if (msgText == null) { 301 msgHtml = getPrimaryBodyPart(); 302 } 303 else { 304 if (this.inlineImages.size() > 0) { 305 msgHtml = new MimeBodyPart(); 306 subContainerHTML.addBodyPart(msgHtml); 307 } 308 else { 309 msgHtml = new MimeBodyPart(); 310 container.addBodyPart(msgHtml, 1); 311 } 312 } 313 314 if(!StringUtil.isEmpty(this.charset)) { 315 msgHtml.setContent( 316 this.html, 317 Email.TEXT_HTML + "; charset=" + this.charset); 318 } 319 else { 320 msgHtml.setContent(this.html, Email.TEXT_HTML); 321 } 322 323 Iterator iter = this.inlineImages.iterator(); 324 while (iter.hasNext()) 325 { 326 subContainerHTML.addBodyPart((BodyPart) iter.next()); 327 } 328 329 if (this.inlineImages.size() > 0) 330 { 331 // add sub container to message 332 this.addPart(subContainerHTML); 333 } 334 } 335 } 336 }