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