1 17 18 package org.sape.carbon.services.email; 19 20 21 import java.io.UnsupportedEncodingException ; 22 import java.net.MalformedURLException ; 23 import java.net.URL ; 24 import java.util.ArrayList ; 25 import java.util.Collection ; 26 import java.util.HashMap ; 27 import java.util.Iterator ; 28 import java.util.Map ; 29 import java.util.Properties ; 30 31 import javax.activation.DataHandler ; 32 import javax.activation.DataSource ; 33 import javax.activation.URLDataSource ; 34 import javax.mail.BodyPart ; 35 import javax.mail.Message ; 36 import javax.mail.MessagingException ; 37 import javax.mail.Multipart ; 38 import javax.mail.Part ; 39 import javax.mail.Session ; 40 import javax.mail.Transport ; 41 import javax.mail.internet.InternetAddress ; 42 import javax.mail.internet.MimeBodyPart ; 43 import javax.mail.internet.MimeMessage ; 44 import javax.mail.internet.MimeMultipart ; 45 import javax.mail.internet.MimeUtility ; 46 47 import org.sape.carbon.core.component.ComponentConfiguration; 48 import org.sape.carbon.core.component.lifecycle.Configurable; 49 import org.sape.carbon.core.component.lifecycle.Startable; 50 import org.sape.carbon.core.config.InvalidConfigurationException; 51 import org.sape.carbon.core.exception.InvalidParameterException; 52 import org.sape.carbon.services.email.util.MailAttachment; 53 import org.sape.carbon.services.email.util.MailContentTypeEnum; 54 55 import org.apache.commons.logging.Log; 56 import org.apache.commons.logging.LogFactory; 57 58 67 public class SynchronousMailService 68 implements MailService, Configurable, Startable { 69 70 73 private Log log = LogFactory.getLog(this.getClass()); 74 75 78 private String smtpHost; 79 80 81 88 private boolean holdConnection; 89 90 91 104 private int retryAttempts; 105 106 107 111 private Session session; 112 113 114 118 private Transport transport; 119 120 121 125 private long sleepRetryTime; 126 127 128 protected static final String CONTENT_TYPE = "Content-Type"; 129 130 131 protected static final String BLANK_STRING = ""; 132 133 146 public void sendMail(MailDataObject mailDataObject) 147 throws MailFailureException { 148 149 Map to = mailDataObject.getToMap(); 151 Map cc = mailDataObject.getCCMap(); 152 Map bcc = mailDataObject.getBCCMap(); 153 Map headers = mailDataObject.getHeaders(); 154 String fromPersonal = mailDataObject.getFromName(); 155 String fromEmail = mailDataObject.getFromEmail(); 156 String subject = mailDataObject.getSubject(); 157 String body = mailDataObject.getBody(); 158 MailContentTypeEnum bodyType = mailDataObject.getBodyType(); 159 String charset = mailDataObject.getCharset(); 160 MailAttachment[] attachments = mailDataObject.getAttachments(); 161 162 Collection errors = checkRequiredFields(to, cc, bcc, fromEmail, 165 bodyType); 166 if (!errors.isEmpty()) { 167 throw new InvalidParameterException(this.getClass(), 168 "Some of the required parameters are not specified : " 169 + processRequiredFieldErrors(errors)); 170 } 171 MimeMessage message = new MimeMessage (this.session); 173 174 try { 175 message.setFrom(new InternetAddress (fromEmail, 177 encodeText(fromPersonal, charset, null))); 178 179 if (to != null) { 181 setAddresses(message, to, Message.RecipientType.TO, charset); 182 } 183 184 if (cc != null) { 186 setAddresses(message, cc, Message.RecipientType.CC, charset); 187 } 188 189 if (bcc != null) { 191 setAddresses(message, bcc, Message.RecipientType.BCC, charset); 192 } 193 194 message.setSubject(subject, charset); 195 196 Iterator iter = null; 197 Map.Entry entry = null; 198 199 if (headers != null) { 201 iter = headers.entrySet().iterator(); 202 while (iter.hasNext()) { 203 entry = (Map.Entry ) iter.next(); 204 message.addHeader((String ) entry.getKey(), 205 (String ) entry.getValue()); 206 } 207 } 208 209 if (attachments != null) { 211 processAttachments(message, body, bodyType, charset, 212 attachments); 213 } else { 214 message.setText(body, charset); 216 217 setContentTypeHeader(message, bodyType, charset); 219 } 220 221 } catch (UnsupportedEncodingException uee) { 222 throw new MailFailureException(this.getClass(), 223 "The charset passed to encode the message is not supported." 224 , uee); 225 } catch (MalformedURLException mue) { 226 throw new MailFailureException(this.getClass(), 227 "Failed to locate one of the attachment passed. " 228 + "Check the path or URL for each attachment.", mue); 229 } catch (MessagingException me) { 230 throw new MailFailureException(this.getClass(), 231 "Failed to create the Mime Message", me); 232 } 233 234 try { 236 send(message); 237 } catch (MessagingException me) { 238 throw new MailFailureException(this.getClass(), 239 "Failed to send the mail", me); 240 } 241 } 242 243 244 261 protected void processAttachments(MimeMessage message, String body, 262 MailContentTypeEnum bodyType, String charset, 263 MailAttachment[] attachments) throws MessagingException , 264 UnsupportedEncodingException , MalformedURLException { 265 266 MimeBodyPart messageBodyPart = new MimeBodyPart (); 268 269 messageBodyPart.setText(body, charset); 271 272 setContentTypeHeader(messageBodyPart, bodyType, charset); 274 275 Multipart multipart = new MimeMultipart (); 277 278 multipart.addBodyPart(messageBodyPart); 279 280 for (int k = 0; k < attachments.length; k++) { 281 multipart.addBodyPart(attach(attachments[k], charset)); 282 } 283 284 message.setContent(multipart); 285 } 286 287 288 299 protected Collection checkRequiredFields(Map to, Map cc, Map bcc, 300 String fromEmail, MailContentTypeEnum bodyType) { 301 302 ArrayList errors = new ArrayList (); 303 304 if (fromEmail == null) { 306 errors.add("You must specify the sender's email id."); 307 } 308 309 if (bodyType == null) { 311 errors.add("You must specify the body type."); 312 } 313 314 HashMap allRecipients = new HashMap (); 316 317 if (to != null) { 321 if (!(to.containsKey(null)) 322 && (!(to.containsKey(BLANK_STRING)))) { 323 324 allRecipients.putAll(to); 325 } 326 } 327 328 if (cc != null) { 329 if (!(cc.containsKey(null)) 330 && (!(cc.containsKey(BLANK_STRING)))) { 331 332 allRecipients.putAll(cc); 333 } 334 } 335 336 if (bcc != null) { 337 if (!(bcc.containsKey(null)) 338 && (!(bcc.containsKey(BLANK_STRING)))) { 339 340 allRecipients.putAll(bcc); 341 } 342 } 343 344 if (allRecipients.isEmpty()) { 345 errors.add("You must specify atleast one recipient"); 346 } 347 348 return errors; 349 } 350 351 352 359 protected String processRequiredFieldErrors(Collection errors) { 360 361 Iterator iterator = errors.iterator(); 362 StringBuffer errorBuffer = new StringBuffer (); 363 364 while (iterator.hasNext()) { 365 errorBuffer.append(iterator.next()).append("\n"); 366 } 367 return errorBuffer.toString(); 368 } 369 370 371 379 protected void setContentTypeHeader(Part part, MailContentTypeEnum 380 bodyType, String charset) throws MessagingException { 381 382 if (charset != null) { 383 part.addHeader(SynchronousMailService.CONTENT_TYPE, 384 bodyType.getName() + "; charset=" + charset); 385 } else { 386 part.addHeader(SynchronousMailService.CONTENT_TYPE, 387 bodyType.getName()); 388 } 389 } 390 391 392 410 protected String encodeText(String text, String charset, 411 String encodingType) throws UnsupportedEncodingException { 412 413 String encodedText = null; 414 415 419 if (text != null) { 420 encodedText = MimeUtility.encodeText(text, charset, encodingType); 421 } 422 423 return encodedText; 424 } 425 426 427 428 private static final String FILE = "file"; 429 430 431 private static final String LOCALHOST = "localhost"; 432 433 434 448 protected BodyPart attach(MailAttachment attachment, String charset) 449 throws MalformedURLException , UnsupportedEncodingException , 450 MessagingException { 451 452 URL url = attachment.getURL(); 454 455 String path = null; 456 457 if (url == null) { 459 path = attachment.getPath(); 460 url = new URL (FILE, LOCALHOST, path); 461 } 462 463 MimeBodyPart mimeBodyPart = new MimeBodyPart (); 465 466 DataSource source = new URLDataSource (url); 468 469 mimeBodyPart.setDataHandler(new DataHandler (source)); 471 472 mimeBodyPart.setFileName(encodeText(attachment.getName(), charset, 473 null)); 474 475 mimeBodyPart.setDescription( 476 encodeText(attachment.getDescription(), charset, null)); 477 478 return mimeBodyPart; 479 } 480 481 482 496 protected void setAddresses(MimeMessage message, Map addresses, 497 Message.RecipientType recipientType, String charset) 498 throws MessagingException , UnsupportedEncodingException { 499 500 Iterator iterator = null; 501 Map.Entry entry = null; 502 InternetAddress address = null; 503 504 iterator = addresses.entrySet().iterator(); 505 while (iterator.hasNext()) { 506 entry = (Map.Entry ) iterator.next(); 507 address = new InternetAddress ((String ) entry.getKey(), 508 encodeText((String ) entry.getValue(), charset, null)); 509 message.addRecipient(recipientType, address); 510 } 511 } 512 513 514 private static final String MAIL_PROTOCOL_KEY = "mail.transport.protocol"; 515 516 517 private static final String MAIL_HOST = "mail.host"; 518 519 520 private static final String SMTP = "smtp"; 521 522 523 526 public void configure(ComponentConfiguration config) 527 throws Exception { 528 529 530 MailConfiguration mailConfig = (MailConfiguration) config; 531 532 this.smtpHost = mailConfig.getSmtpHost(); 534 this.holdConnection = mailConfig.getHoldConnection(); 535 this.retryAttempts = mailConfig.getRetryAttempts(); 536 537 if (this.retryAttempts < 0) { 539 throw new InvalidConfigurationException(this.getClass(), 540 mailConfig.getConfigurationName(), 541 "RetryAttempts", "Retry Attempts should be >= 0"); 542 } 543 544 if (this.retryAttempts > 0) { 546 this.sleepRetryTime = mailConfig.getSleepTimeInMilliSecs(); 547 } 548 549 if (sleepRetryTime < 0) { 551 throw new InvalidConfigurationException(this.getClass(), 552 mailConfig.getConfigurationName(), 553 "SleepTimeInMilliSecs", "sleep time should be >= 0"); 554 } 555 556 Properties props = new Properties (); 557 props.put(MAIL_PROTOCOL_KEY, SMTP); 559 props.put(MAIL_HOST, this.smtpHost); 560 561 569 this.session = Session.getInstance(props, null); 570 this.session.setDebug(mailConfig.getJavaMailDebugMode()); 571 572 this.transport = this.session.getTransport(); 575 } 576 577 578 584 protected void send(MimeMessage message) throws MessagingException { 585 586 int attempts = 0; 587 boolean messageSent = false; 588 MessagingException exception = null; 589 590 while (attempts < (this.retryAttempts + 1) && !messageSent) { 591 try { 592 sendInternal(message); 593 messageSent = true; 594 } catch (MessagingException me) { 595 if (this.transport.isConnected()) { 597 this.transport.close(); 598 } 599 try { 601 Thread.sleep(this.sleepRetryTime); 602 } catch (InterruptedException ie) { 603 604 } 605 606 exception = me; 608 attempts++; 609 } 610 } 611 612 if (!messageSent) { 613 if (log.isWarnEnabled()) { 614 log.warn("unable to send the message :" + message); 615 } 616 617 throw exception; 618 } else { 619 if (log.isInfoEnabled()) { 620 log.info("sent the message:" + message); 621 } 622 } 623 } 624 625 626 638 protected void sendInternal(MimeMessage message) 639 throws MessagingException { 640 641 synchronized (this.transport) { 642 if (!this.transport.isConnected()) { 644 this.transport.connect(); 645 } 646 this.transport.sendMessage(message, message.getAllRecipients()); 648 if (!this.holdConnection) { 650 this.transport.close(); 651 } 652 } 653 } 654 655 656 659 public void stop() throws Exception { 660 661 if (this.transport != null && this.transport.isConnected()) { 663 transport.close(); 664 } 665 } 666 667 668 671 public void start() { 672 } 674 } 675 | Popular Tags |