001 package railo.runtime.tag; 002 003 004 import javax.mail.internet.InternetAddress; 005 006 import railo.commons.io.res.Resource; 007 import railo.commons.io.res.util.ResourceUtil; 008 import railo.commons.lang.StringUtil; 009 import railo.runtime.config.ConfigImpl; 010 import railo.runtime.exp.ApplicationException; 011 import railo.runtime.exp.ExpressionException; 012 import railo.runtime.exp.PageException; 013 import railo.runtime.ext.tag.BodyTagImpl; 014 import railo.runtime.net.mail.MailException; 015 import railo.runtime.net.mail.MailPart; 016 import railo.runtime.net.smtp.SMTPClient; 017 import railo.runtime.op.Caster; 018 import railo.runtime.op.Decision; 019 // TODO test proxy 020 /** 021 * 022 * Sends e-mail messages by an SMTP server. 023 * 024 * 025 * 026 **/ 027 public final class Mail extends BodyTagImpl { 028 029 /** Specifies the query column to use when you group sets of records together to send as an e-mail 030 ** message. For example, if you send a set of billing statements to customers, you might group on 031 ** "Customer_ID." The group attribute, which is case sensitive, eliminates adjacent duplicates when the 032 ** data is sorted by the specified field. See the Usage section for exceptions. */ 033 private String group; 034 035 /** Boolean indicating whether to group with regard to case or not. The default value is YES; 036 ** case is considered while grouping. If the query attribute specifies a query object that was generated 037 ** by a case-insensitive SQL query, set the groupCaseSensitive attribute to NO to keep the recordset 038 ** intact. */ 039 private boolean groupcasesensitive; 040 041 /** The name of the cfquery from which to draw data for message(s) to send. Specify this 042 ** attribute to send more than one mail message, or to send the results of a query within a message. */ 043 private String query; 044 045 /** Specifies the maximum number of e-mail messages to send. */ 046 private double maxrows; 047 048 /** Specifies the row in the query to start from. */ 049 private double startrow; 050 051 052 053 //private railo.runtime.mail.Mail mail=new railo.runtime.mail.Mail(); 054 private SMTPClient smtp=new SMTPClient(); 055 private railo.runtime.net.mail.MailPart part=null;//new railo.runtime.mail.MailPart("UTF-8"); 056 057 private String charset; 058 059 private int priority; 060 061 private boolean remove; 062 063 064 065 /** 066 * @see javax.servlet.jsp.tagext.Tag#release() 067 */ 068 public void release() { 069 super.release(); 070 // do not clear because spooler 071 //mail=new railo.runtime.mail.Mail(); 072 smtp=new SMTPClient(); 073 part=null;//new railo.runtime.mail.MailPart("UTF-8"); 074 group=null; 075 groupcasesensitive=false; 076 query=null; 077 maxrows=0d; 078 startrow=0d; 079 charset=null; 080 remove=false; 081 } 082 083 084 /** 085 * @param remove the remove to set 086 */ 087 public void setRemove(boolean remove) { 088 this.remove = remove; 089 } 090 091 092 /** 093 * @param proxyserver The proxyserver to set. 094 * @throws ApplicationException 095 */ 096 public void setProxyserver(String proxyserver) throws ApplicationException { 097 try { 098 smtp.getProxyData().setServer(proxyserver); 099 } catch (Exception e) { 100 throw new ApplicationException("attribute [proxyserver] of the tag [mail] is invalid",e.getMessage()); 101 } 102 } 103 104 /** set the value proxyport 105 * The port number on the proxy server from which the object is requested. Default is 80. When 106 * used with resolveURL, the URLs of retrieved documents that specify a port number are automatically 107 * resolved to preserve links in the retrieved document. 108 * @param proxyport value to set 109 * @throws ApplicationException 110 **/ 111 public void setProxyport(double proxyport) throws ApplicationException { 112 try { 113 smtp.getProxyData().setPort((int)proxyport); 114 } catch (Exception e) { 115 throw new ApplicationException("attribute [proxyport] of the tag [mail] is invalid",e.getMessage()); 116 } 117 } 118 119 /** set the value username 120 * When required by a proxy server, a valid username. 121 * @param proxyuser value to set 122 * @throws ApplicationException 123 **/ 124 public void setProxyuser(String proxyuser) throws ApplicationException { 125 try { 126 smtp.getProxyData().setUsername(proxyuser); 127 } catch (Exception e) { 128 throw new ApplicationException("attribute [proxyuser] of the tag [mail] is invalid",e.getMessage()); 129 } 130 } 131 132 133 /** set the value password 134 * When required by a proxy server, a valid password. 135 * @param proxypassword value to set 136 * @throws ApplicationException 137 **/ 138 public void setProxypassword(String proxypassword) throws ApplicationException { 139 try { 140 smtp.getProxyData().setPassword(proxypassword); 141 } catch (Exception e) { 142 throw new ApplicationException("attribute [proxypassword] of the tag [mail] is invalid",e.getMessage()); 143 } 144 } 145 146 147 148 /** set the value from 149 * The sender of the e-mail message. 150 * @param strForm value to set 151 * @throws PageException 152 **/ 153 public void setFrom(Object from) throws PageException { 154 if(StringUtil.isEmpty(from)) return; 155 try { 156 smtp.setFrom(from); 157 } catch (Exception e) { 158 throw Caster.toPageException(e); 159 } 160 } 161 162 /** set the value to 163 * The name of the e-mail message recipient. 164 * @param strTo value to set 165 * @throws ApplicationException 166 **/ 167 public void setTo(Object to) throws ApplicationException { 168 if(StringUtil.isEmpty(to)) return; 169 try { 170 smtp.addTo(to); 171 } catch (Exception e) { 172 throw new ApplicationException("attribute [to] of the tag [mail] is invalid",e.getMessage()); 173 } 174 } 175 176 /** set the value cc 177 * Indicates addresses to copy the e-mail message to; "cc" stands for "carbon copy." 178 * @param strCc value to set 179 * @throws ApplicationException 180 **/ 181 public void setCc(Object cc) throws ApplicationException { 182 if(StringUtil.isEmpty(cc)) return; 183 try { 184 smtp.addCC(cc); 185 } catch (Exception e) { 186 throw new ApplicationException("attribute [cc] of the tag [mail] is invalid",e.getMessage()); 187 } 188 } 189 190 191 192 /** set the value bcc 193 * Indicates addresses to copy the e-mail message to, without listing them in the message header. 194 * "bcc" stands for "blind carbon copy." 195 * @param strBcc value to set 196 * @throws ApplicationException 197 **/ 198 public void setBcc(Object bcc) throws ApplicationException { 199 if(StringUtil.isEmpty(bcc)) return; 200 try { 201 smtp.addBCC(bcc); 202 } catch (Exception e) { 203 throw new ApplicationException("attribute [bcc] of the tag [mail] is invalid",e.getMessage()); 204 } 205 } 206 207 /** 208 * @param strFailto The failto to set. 209 * @throws ApplicationException 210 */ 211 public void setFailto(Object failto) throws ApplicationException { 212 if(StringUtil.isEmpty(failto)) return; 213 try { 214 smtp.addFailTo(failto); 215 } catch (Exception e) { 216 throw new ApplicationException("attribute [failto] of the tag [mail] is invalid",e.getMessage()); 217 } 218 } 219 /** 220 * @param strReplyto The replyto to set. 221 * @throws ApplicationException 222 */ 223 public void setReplyto(Object replyto) throws ApplicationException { 224 if(StringUtil.isEmpty(replyto)) return; 225 try { 226 smtp.addReplyTo(replyto); 227 } catch (Exception e) { 228 throw new ApplicationException("attribute [replyto] of the tag [mail] is invalid",e.getMessage()); 229 } 230 } 231 232 /** set the value type 233 * Specifies extended type attributes for the message. 234 * @param type value to set 235 * @throws ApplicationException 236 **/ 237 public void setType(String type) throws ApplicationException { 238 type=type.toLowerCase().trim(); 239 if(type.equals("text/plain") || type.equals("plain") || type.equals("text")) 240 getPart().isHTML(false); 241 //mail.setType(railo.runtime.mail.Mail.TYPE_TEXT); 242 else if(type.equals("text/html") || type.equals("html") || type.equals("htm")) 243 getPart().isHTML(true); 244 else 245 throw new ApplicationException("attribute type of tag mail has a invalid values","valid values are [plain,text,html] but value is now ["+type+"]"); 246 //throw new ApplicationException(("invalid type "+type); 247 } 248 249 /** set the value subject 250 * The subject of the mail message. This field may be driven dynamically on 251 * a message-by-message basis 252 * @param subject value to set 253 **/ 254 public void setSubject(String subject) { 255 smtp.setSubject(subject); 256 } 257 /** 258 * @param username The username to set. 259 */ 260 public void setUsername(String username) { 261 smtp.setUsername(username); 262 } 263 /** 264 * @param password The password to set. 265 */ 266 public void setPassword(String password) { 267 smtp.setPassword(password); 268 } 269 270 /** set the value mimeattach 271 * Specifies the path of the file to be attached to the e-mail message. An attached file 272 * is MIME-encoded. 273 * @param strMimeattach value to set 274 * @param type mimetype of the file 275 * @param contentID 276 * @param disposition 277 * @throws PageException 278 **/ 279 public void setMimeattach(String strMimeattach, String type, String disposition, String contentID,boolean removeAfterSend) throws PageException { 280 Resource file=ResourceUtil.toResourceNotExisting(pageContext,strMimeattach); 281 pageContext.getConfig().getSecurityManager().checkFileLocation(file); 282 if(!file.exists()) 283 throw new ApplicationException("can't attach file "+strMimeattach+", this file doesn't exist"); 284 285 286 smtp.addAttachment(file,type,disposition,contentID,removeAfterSend); 287 288 } 289 public void setMimeattach(String strMimeattach) throws PageException { 290 setMimeattach(strMimeattach, "", null, null,false); 291 } 292 293 /** 294 * @param spoolenable The spoolenable to set. 295 */ 296 public void setSpoolenable(boolean spoolenable) { 297 smtp.setSpoolenable(spoolenable); 298 } 299 300 /** set the value server 301 * @param strServer value to set 302 * @throws PageException 303 **/ 304 public void setServer(String strServer) throws PageException { 305 smtp.setHost(strServer); 306 } 307 308 /** set the value mailerid 309 * @param mailerid value to set 310 **/ 311 public void setMailerid(String mailerid) { 312 smtp.setXMailer(mailerid); 313 } 314 315 /** set the value port 316 * The TCP/IP port on which the SMTP server listens for requests. This is normally 25. 317 * @param port value to set 318 **/ 319 public void setPort(double port) { 320 smtp.setPort((int)port); 321 } 322 323 /** 324 * @param wraptext The wraptext to set. 325 */ 326 public void setWraptext(double wraptext) { 327 getPart().setWraptext((int)wraptext); 328 } 329 330 /** set the value timeout 331 * The number of seconds to wait before timing out the connection to the SMTP server. 332 * @param timeout value to set 333 **/ 334 public void setTimeout(double timeout) { 335 smtp.setTimeout((int)(timeout*1000)); 336 } 337 338 /** 339 * @param charset The charset to set. 340 */ 341 public void setCharset(String charset) { 342 this.charset=charset; 343 } 344 345 /** set the value group 346 * Specifies the query column to use when you group sets of records together to send as an e-mail 347 * message. For example, if you send a set of billing statements to customers, you might group on 348 * "Customer_ID." The group attribute, which is case sensitive, eliminates adjacent duplicates when the 349 * data is sorted by the specified field. See the Usage section for exceptions. 350 * @param group value to set 351 **/ 352 public void setGroup(String group) { 353 this.group=group; 354 } 355 356 /** set the value groupcasesensitive 357 * Boolean indicating whether to group with regard to case or not. The default value is YES; 358 * case is considered while grouping. If the query attribute specifies a query object that was generated 359 * by a case-insensitive SQL query, set the groupCaseSensitive attribute to NO to keep the recordset 360 * intact. 361 * @param groupcasesensitive value to set 362 **/ 363 public void setGroupcasesensitive(boolean groupcasesensitive) { 364 this.groupcasesensitive=groupcasesensitive; 365 } 366 367 /** set the value query 368 * The name of the cfquery from which to draw data for message(s) to send. Specify this 369 * attribute to send more than one mail message, or to send the results of a query within a message. 370 * @param query value to set 371 **/ 372 public void setQuery(String query) { 373 this.query=query; 374 } 375 376 /** set the value maxrows 377 * Specifies the maximum number of e-mail messages to send. 378 * @param maxrows value to set 379 **/ 380 public void setMaxrows(double maxrows) { 381 this.maxrows=maxrows; 382 } 383 384 385 public void setTls(boolean tls) { 386 smtp.setTLS(tls); 387 } 388 389 public void setUsetls(boolean tls) { 390 smtp.setTLS(tls); 391 } 392 393 public void setStarttls(boolean tls) { 394 smtp.setTLS(tls); 395 } 396 397 public void setSsl(boolean ssl) { 398 smtp.setSSL(ssl); 399 } 400 401 public void setUsessl(boolean ssl) { 402 smtp.setSSL(ssl); 403 } 404 405 public void setSecure(boolean ssl) { 406 smtp.setSSL(ssl); 407 } 408 public void setPriority(String strPriority) throws ExpressionException { 409 strPriority=strPriority.trim().toLowerCase(); 410 boolean valid=true; 411 if(Decision.isNumeric(strPriority)) { 412 int p=Caster.toIntValue(strPriority,-1); 413 if(p<1 || p>5)valid=false; 414 else this.priority=p; 415 } 416 else { 417 if("highest".equals(strPriority))priority=1; 418 else if("urgent".equals(strPriority))priority=1; 419 else if("high".equals(strPriority))priority=2; 420 else if("normal".equals(strPriority))priority=3; 421 else if("low".equals(strPriority))priority=4; 422 else if("lowest".equals(strPriority))priority=5; 423 else if("non-urgent".equals(strPriority))priority=5; 424 else if("none-urgent".equals(strPriority))priority=5; 425 else valid=false; 426 } 427 428 if(!valid)throw new ExpressionException("the value of attribute priority is invalid ["+strPriority+"], " + 429 "the value should be an integer between [1-5] or " + 430 "one of the following [highest,urgent,high,normal,low,lowest,non-urgent]"); 431 432 } 433 434 /** set the value startrow 435 * Specifies the row in the query to start from. 436 * @param startrow value to set 437 **/ 438 public void setStartrow(double startrow) { 439 this.startrow=startrow; 440 } 441 442 /** 443 * @param part 444 */ 445 public void addPart(MailPart part) { 446 String type = part.getType(); 447 if(StringUtil.isEmpty(part.getCharset())) part.setCharset(getCharset()); 448 if(type!=null && (type.equals("text/plain") || type.equals("plain") || type.equals("text"))){ 449 part.isHTML(false); 450 addClassicBodyPart(part); 451 } 452 else if(type!=null && (type.equals("text/html") || type.equals("html") || type.equals("htm"))){ 453 part.isHTML(true); 454 addClassicBodyPart(part); 455 } 456 else { 457 addBodyPart(part); 458 } 459 } 460 461 // this was not supported in prior releases 462 private void addBodyPart(MailPart part) { 463 smtp.setPart(part); 464 } 465 466 /** 467 * @param part 468 */ 469 private void addClassicBodyPart(MailPart part) { 470 if(part.isHTML()) { 471 if(!smtp.hasHTMLText())smtp.setHTMLText(part.getBody(), part.getCharset()); 472 } 473 else { 474 if(!smtp.hasPlainText())smtp.setPlainText(part.getBody(), part.getCharset()); 475 } 476 } 477 478 479 /** 480 * @throws ApplicationException 481 * @see javax.servlet.jsp.tagext.Tag#doStartTag() 482 */ 483 public int doStartTag() throws ApplicationException { 484 if(isEmpty(smtp.getTos()) && isEmpty(smtp.getCcs()) && isEmpty(smtp.getBccs())) 485 throw new ApplicationException("One of the following attribtues must be defined [to, cc, bcc]"); 486 487 return EVAL_BODY_BUFFERED; 488 } 489 490 private boolean isEmpty(InternetAddress[] addrs) { 491 return addrs==null || addrs.length==0; 492 } 493 494 495 /** 496 * @see javax.servlet.jsp.tagext.BodyTag#doInitBody() 497 */ 498 public void doInitBody() { 499 500 } 501 502 /** 503 * @see javax.servlet.jsp.tagext.BodyTag#doAfterBody() 504 */ 505 public int doAfterBody() { 506 getPart().setBody(bodyContent.getString()); 507 smtp.setCharset(getCharset()); 508 getPart().setCharset(getCharset()); 509 addClassicBodyPart(getPart()); 510 return SKIP_BODY; 511 } 512 513 /** 514 * @see javax.servlet.jsp.tagext.Tag#doEndTag() 515 */ 516 public int doEndTag() throws PageException { 517 smtp.setTimeZone(pageContext.getTimeZone()); 518 try { 519 smtp.send((ConfigImpl) pageContext.getConfig()); 520 } 521 catch (MailException e) { 522 throw Caster.toPageException(e); 523 } 524 return EVAL_PAGE; 525 } 526 527 /** 528 * sets a mail param 529 * @param type 530 * @param file 531 * @param name 532 * @param value 533 * @param contentID 534 * @param disposition 535 * @throws PageException 536 */ 537 public void setParam(String type, String file, String name, String value, String disposition, String contentID,Boolean oRemoveAfterSend) throws PageException { 538 if(file!=null){ 539 boolean removeAfterSend=(oRemoveAfterSend==null)?remove:oRemoveAfterSend.booleanValue(); 540 541 setMimeattach(file,type,disposition,contentID,removeAfterSend); 542 } 543 else { 544 if(name.equalsIgnoreCase("bcc")) setBcc(value); 545 else if(name.equalsIgnoreCase("cc")) setCc(value); 546 else if(name.equalsIgnoreCase("charset")) setCharset(value); 547 else if(name.equalsIgnoreCase("failto")) setFailto(value); 548 else if(name.equalsIgnoreCase("from")) setFrom(value); 549 else if(name.equalsIgnoreCase("mailerid")) setMailerid(value); 550 else if(name.equalsIgnoreCase("mimeattach"))setMimeattach(value); 551 else if(name.equalsIgnoreCase("priority")) setPriority(value); 552 else if(name.equalsIgnoreCase("replyto")) setReplyto(value); 553 else if(name.equalsIgnoreCase("subject")) setSubject(value); 554 else if(name.equalsIgnoreCase("to")) setTo(value); 555 556 else smtp.addHeader(name,value); 557 } 558 } 559 560 private railo.runtime.net.mail.MailPart getPart() { 561 if(part==null)part=new railo.runtime.net.mail.MailPart(pageContext.getConfig().getMailDefaultEncoding()); 562 return part; 563 } 564 565 566 /** 567 * @return the charset 568 */ 569 public String getCharset() { 570 if(charset==null)charset=pageContext.getConfig().getMailDefaultEncoding(); 571 return charset; 572 } 573 }