001/* 002 * (C) Copyright 2006-2011 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * npaslaru, tmartins, jcarsique 018 * 019 */ 020 021package org.nuxeo.ecm.platform.ec.notification.email; 022 023import java.io.IOException; 024import java.io.Serializable; 025import java.io.StringReader; 026import java.io.StringWriter; 027import java.io.Writer; 028import java.util.Collection; 029import java.util.Date; 030import java.util.HashMap; 031import java.util.Map; 032import java.util.Properties; 033 034import javax.mail.Authenticator; 035import javax.mail.Message; 036import javax.mail.MessagingException; 037import javax.mail.Session; 038import javax.mail.Transport; 039import javax.mail.internet.InternetAddress; 040import javax.mail.internet.MimeMessage; 041import javax.naming.InitialContext; 042import javax.naming.NamingException; 043import javax.security.auth.login.LoginContext; 044import javax.security.auth.login.LoginException; 045 046import org.apache.commons.logging.Log; 047import org.apache.commons.logging.LogFactory; 048import org.mvel2.MVEL; 049import org.nuxeo.ecm.core.api.DocumentModel; 050import org.nuxeo.ecm.platform.ec.notification.NotificationConstants; 051import org.nuxeo.ecm.platform.ec.notification.service.NotificationService; 052import org.nuxeo.ecm.platform.ec.notification.service.NotificationServiceHelper; 053import org.nuxeo.ecm.platform.rendering.RenderingException; 054import org.nuxeo.ecm.platform.rendering.RenderingResult; 055import org.nuxeo.ecm.platform.rendering.RenderingService; 056import org.nuxeo.ecm.platform.rendering.impl.DocumentRenderingContext; 057import org.nuxeo.runtime.api.Framework; 058 059import freemarker.template.Configuration; 060import freemarker.template.Template; 061import freemarker.template.TemplateException; 062 063/** 064 * Class EmailHelper. 065 * <p> 066 * An email helper: 067 * <p> 068 * 069 * <pre> 070 * Hashtable mail = new Hashtable(); 071 * mail.put("from", "dion@almaer.com"); 072 * mail.put("to", "dion@almaer.com"); 073 * mail.put("subject", "a subject"); 074 * mail.put("template", "a template name"); 075 * <p> 076 * EmailHelper.sendmail(mail); 077 * </pre> 078 * 079 * Currently only supports one email in to address 080 */ 081public class EmailHelper { 082 083 private static final Log log = LogFactory.getLog(EmailHelper.class); 084 085 // used for loading templates from strings 086 private final Configuration stringCfg = new Configuration(); 087 088 protected static boolean javaMailNotAvailable = false; 089 090 /* Only static methods here chaps */ 091 public EmailHelper() { 092 } 093 094 /** 095 * Static Method: sendmail(Map mail). 096 * 097 * @param mail A map of the settings 098 */ 099 public void sendmail(Map<String, Object> mail) throws MessagingException { 100 try { 101 sendmail0(mail); 102 } catch (LoginException | IOException | TemplateException | RenderingException e) { 103 throw new MessagingException(e.getMessage(), e); 104 } 105 } 106 107 protected void sendmail0(Map<String, Object> mail) throws MessagingException, IOException, TemplateException, 108 LoginException, RenderingException { 109 110 Session session = getSession(); 111 if (javaMailNotAvailable || session == null) { 112 log.warn("Not sending email since JavaMail is not configured"); 113 return; 114 } 115 116 // Construct a MimeMessage 117 MimeMessage msg = new MimeMessage(session); 118 msg.setFrom(new InternetAddress(session.getProperty("mail.from"))); 119 Object to = mail.get("mail.to"); 120 if (!(to instanceof String)) { 121 log.error("Invalid email recipient: " + to); 122 return; 123 } 124 msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse((String) to, false)); 125 126 RenderingService rs = Framework.getService(RenderingService.class); 127 128 DocumentRenderingContext context = new DocumentRenderingContext(); 129 context.remove("doc"); 130 context.putAll(mail); 131 context.setDocument((DocumentModel) mail.get("document")); 132 context.put("Runtime", Framework.getRuntime()); 133 134 String customSubjectTemplate = (String) mail.get(NotificationConstants.SUBJECT_TEMPLATE_KEY); 135 if (customSubjectTemplate == null) { 136 String subjTemplate = (String) mail.get(NotificationConstants.SUBJECT_KEY); 137 Template templ = new Template("name", new StringReader(subjTemplate), stringCfg); 138 139 Writer out = new StringWriter(); 140 templ.process(mail, out); 141 out.flush(); 142 143 msg.setSubject(out.toString(), "UTF-8"); 144 } else { 145 rs.registerEngine(new NotificationsRenderingEngine(customSubjectTemplate)); 146 147 LoginContext lc = Framework.login(); 148 149 Collection<RenderingResult> results = rs.process(context); 150 String subjectMail = "<HTML><P>No parsing Succeded !!!</P></HTML>"; 151 152 for (RenderingResult result : results) { 153 subjectMail = (String) result.getOutcome(); 154 } 155 subjectMail = NotificationServiceHelper.getNotificationService().getEMailSubjectPrefix() + subjectMail; 156 msg.setSubject(subjectMail, "UTF-8"); 157 158 lc.logout(); 159 } 160 161 msg.setSentDate(new Date()); 162 163 rs.registerEngine(new NotificationsRenderingEngine((String) mail.get(NotificationConstants.TEMPLATE_KEY))); 164 165 LoginContext lc = Framework.login(); 166 167 Collection<RenderingResult> results = rs.process(context); 168 String bodyMail = "<HTML><P>No parsing Succedeed !!!</P></HTML>"; 169 170 for (RenderingResult result : results) { 171 bodyMail = (String) result.getOutcome(); 172 } 173 174 lc.logout(); 175 176 rs.unregisterEngine("ftl"); 177 178 msg.setContent(bodyMail, "text/html; charset=utf-8"); 179 180 // Send the message. 181 Transport.send(msg); 182 } 183 184 /** 185 * Gets the session from the JNDI. 186 */ 187 private static Session getSession() { 188 Session session = null; 189 if (javaMailNotAvailable) { 190 return null; 191 } 192 // First, try to get the session from JNDI, as would be done under J2EE. 193 try { 194 NotificationService service = (NotificationService) Framework.getRuntime().getComponent( 195 NotificationService.NAME); 196 InitialContext ic = new InitialContext(); 197 session = (Session) ic.lookup(service.getMailSessionJndiName()); 198 } catch (NamingException ex) { 199 log.warn("Unable to find Java mail API", ex); 200 javaMailNotAvailable = true; 201 } 202 203 return session; 204 } 205 206 /** 207 * Instantiate a new session that authenticate given the protocol's properties. Initialize also the default 208 * transport protocol handler according to the properties. 209 * 210 * @since 5.6 211 */ 212 public static Session newSession(Properties props) { 213 Authenticator authenticator = new EmailAuthenticator(props); 214 Session session = Session.getDefaultInstance(props, authenticator); 215 String protocol = props.getProperty("mail.transport.protocol"); 216 if (protocol != null && protocol.length() > 0) { 217 session.setProtocolForAddress("rfc822", protocol); 218 } 219 return session; 220 } 221 222 protected Map<String, Object> initMvelBindings(Map<String, Serializable> infos) { 223 Map<String, Object> map = new HashMap<String, Object>(); 224 map.put("NotificationContext", infos); 225 return map; 226 } 227 228 /*** 229 * Evaluates a MVEL expression within some context infos accessible on the "NotificationContext" object. Returns 230 * null if the result is not evaluated to a String 231 * 232 * @param expr 233 * @param ctx 234 * @return 235 * @since 5.6 236 */ 237 public String evaluateMvelExpresssion(String expr, Map<String, Serializable> ctx) { 238 // check to see if there is a dynamic MVEL expr 239 Serializable compiledExpr = MVEL.compileExpression(expr); 240 Object result = MVEL.executeExpression(compiledExpr, initMvelBindings(ctx)); 241 if (result instanceof String) { 242 return (String) result; 243 } 244 return null; 245 } 246}