001/* 002 * (C) Copyright 2006-2019 Nuxeo (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.Message; 035import javax.mail.MessagingException; 036import javax.mail.Session; 037import javax.mail.Transport; 038import javax.mail.internet.InternetAddress; 039import javax.mail.internet.MimeMessage; 040 041import org.apache.commons.logging.Log; 042import org.apache.commons.logging.LogFactory; 043import org.mvel2.MVEL; 044import org.nuxeo.ecm.core.api.DocumentModel; 045import org.nuxeo.ecm.core.api.NuxeoException; 046import org.nuxeo.ecm.platform.ec.notification.NotificationConstants; 047import org.nuxeo.ecm.platform.ec.notification.service.NotificationService; 048import org.nuxeo.ecm.platform.ec.notification.service.NotificationServiceHelper; 049import org.nuxeo.ecm.platform.notification.api.NotificationManager; 050import org.nuxeo.ecm.platform.rendering.RenderingException; 051import org.nuxeo.ecm.platform.rendering.RenderingResult; 052import org.nuxeo.ecm.platform.rendering.RenderingService; 053import org.nuxeo.ecm.platform.rendering.impl.DocumentRenderingContext; 054import org.nuxeo.mail.MailSessionBuilder; 055import org.nuxeo.runtime.api.Framework; 056import org.nuxeo.runtime.api.login.NuxeoLoginContext; 057 058import freemarker.template.Configuration; 059import freemarker.template.Template; 060import freemarker.template.TemplateException; 061 062/** 063 * Class EmailHelper. 064 * <p> 065 * An email helper: 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("template", "a template name"); 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(Configuration.VERSION_2_3_0); 085 086 protected static boolean javaMailNotAvailable = false; 087 088 /** 089 * Static Method: sendmail(Map mail). 090 * 091 * @param mail A map of the settings 092 */ 093 public void sendmail(Map<String, Object> mail) throws MessagingException { 094 try { 095 sendmail0(mail); 096 } catch (IOException | TemplateException | RenderingException e) { 097 throw new MessagingException(e.getMessage(), e); 098 } 099 } 100 101 protected void sendmail0(Map<String, Object> mail) 102 throws MessagingException, IOException, TemplateException, RenderingException { 103 104 Session session = getSession(); 105 if (javaMailNotAvailable || session == null) { 106 log.warn("Not sending email since JavaMail is not configured"); 107 return; 108 } 109 110 // Construct a MimeMessage 111 MimeMessage msg = new MimeMessage(session); 112 msg.setFrom(new InternetAddress(session.getProperty("mail.from"))); 113 Object to = mail.get("mail.to"); 114 if (!(to instanceof String)) { 115 log.error("Invalid email recipient: " + to); 116 return; 117 } 118 msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse((String) to, false)); 119 120 RenderingService rs = Framework.getService(RenderingService.class); 121 122 DocumentRenderingContext context = new DocumentRenderingContext(); 123 context.putAll(mail); 124 context.setDocument((DocumentModel) mail.get("document")); 125 context.put("Runtime", Framework.getRuntime()); 126 127 String customSubjectTemplate = (String) mail.get(NotificationConstants.SUBJECT_TEMPLATE_KEY); 128 if (customSubjectTemplate == null) { 129 String subjTemplate = (String) mail.get(NotificationConstants.SUBJECT_KEY); 130 Template templ = new Template("name", new StringReader(subjTemplate), stringCfg); 131 132 Writer out = new StringWriter(); 133 templ.process(mail, out); 134 out.flush(); 135 136 msg.setSubject(out.toString(), "UTF-8"); 137 } else { 138 rs.registerEngine(new NotificationsRenderingEngine(customSubjectTemplate)); 139 140 try (NuxeoLoginContext loginContext = Framework.loginSystem()) { 141 Collection<RenderingResult> results = rs.process(context); 142 String subjectMail = "<HTML><P>No parsing Succeded !!!</P></HTML>"; 143 144 for (RenderingResult result : results) { 145 subjectMail = (String) result.getOutcome(); 146 } 147 subjectMail = NotificationServiceHelper.getNotificationService().getEMailSubjectPrefix() + subjectMail; 148 msg.setSubject(subjectMail, "UTF-8"); 149 } 150 } 151 152 msg.setSentDate(new Date()); 153 154 String template = (String) mail.get(NotificationConstants.TEMPLATE_KEY); 155 rs.registerEngine(new NotificationsRenderingEngine(template)); 156 157 String bodyMail = "<HTML><P>No parsing Succedeed !!!</P></HTML>"; 158 159 Collection<RenderingResult> results; 160 try (NuxeoLoginContext lc = Framework.loginSystem()) { 161 results = rs.process(context); 162 } 163 for (RenderingResult result : results) { 164 bodyMail = (String) result.getOutcome(); 165 } 166 167 rs.unregisterEngine(template); 168 169 msg.setContent(bodyMail, "text/html; charset=utf-8"); 170 171 // Send the message. 172 Transport.send(msg); 173 } 174 175 /** 176 * Gets the session from the JNDI. 177 */ 178 private static Session getSession() { 179 if (!javaMailNotAvailable) { 180 // First, try to get the session from JNDI, as would be done under J2EE. 181 try { 182 NotificationService service = (NotificationService) Framework.getService(NotificationManager.class); 183 return MailSessionBuilder.fromJndi(service.getMailSessionJndiName()).build(); 184 } catch (NuxeoException ex) { 185 log.warn("Unable to find Java mail API", ex); 186 javaMailNotAvailable = true; 187 } 188 } 189 return null; 190 } 191 192 /** 193 * Instantiates a new session that authenticates given the protocol's properties. Initializes also the default 194 * transport protocol handler according to the properties. 195 * 196 * @since 5.6 197 * @deprecated since 11.1, use {@link MailSessionBuilder} 198 */ 199 @Deprecated(since = "11.1") 200 public static Session newSession(Properties props) { 201 return MailSessionBuilder.fromProperties(props).build(); 202 } 203 204 protected Map<String, Object> initMvelBindings(Map<String, Serializable> infos) { 205 Map<String, Object> map = new HashMap<>(); 206 map.put("NotificationContext", infos); 207 return map; 208 } 209 210 /*** 211 * Evaluates a MVEL expression within some context infos accessible on the "NotificationContext" object. Returns 212 * null if the result is not evaluated to a String 213 * 214 * @since 5.6 215 */ 216 public String evaluateMvelExpresssion(String expr, Map<String, Serializable> ctx) { 217 // check to see if there is a dynamic MVEL expr 218 Serializable compiledExpr = MVEL.compileExpression(expr); 219 Object result = MVEL.executeExpression(compiledExpr, initMvelBindings(ctx)); 220 if (result instanceof String) { 221 return (String) result; 222 } 223 return null; 224 } 225}