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