/*
* (C) Copyright 2006-2011 Nuxeo SA (http://nuxeo.com/) and others.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Contributors:
* npaslaru, tmartins, jcarsique
*
*/
package org.nuxeo.ecm.platform.ec.notification.email;
import java.io.IOException;
import java.io.Serializable;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.mvel2.MVEL;
import org.nuxeo.ecm.core.api.DocumentModel;
import org.nuxeo.ecm.platform.ec.notification.NotificationConstants;
import org.nuxeo.ecm.platform.ec.notification.service.NotificationService;
import org.nuxeo.ecm.platform.ec.notification.service.NotificationServiceHelper;
import org.nuxeo.ecm.platform.rendering.RenderingException;
import org.nuxeo.ecm.platform.rendering.RenderingResult;
import org.nuxeo.ecm.platform.rendering.RenderingService;
import org.nuxeo.ecm.platform.rendering.impl.DocumentRenderingContext;
import org.nuxeo.runtime.api.Framework;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
/**
* Class EmailHelper.
* <p>
* An email helper:
* <p>
*
* <pre>
* Hashtable mail = new Hashtable();
* mail.put("from", "dion@almaer.com");
* mail.put("to", "dion@almaer.com");
* mail.put("subject", "a subject");
* mail.put("template", "a template name");
* <p>
* EmailHelper.sendmail(mail);
* </pre>
*
* Currently only supports one email in to address
*/
public class EmailHelper {
private static final Log log = LogFactory.getLog(EmailHelper.class);
// used for loading templates from strings
private final Configuration stringCfg = new Configuration();
protected static boolean javaMailNotAvailable = false;
/* Only static methods here chaps */
public EmailHelper() {
}
/**
* Static Method: sendmail(Map mail).
*
* @param mail A map of the settings
*/
public void sendmail(Map<String, Object> mail) throws MessagingException {
try {
sendmail0(mail);
} catch (LoginException | IOException | TemplateException | RenderingException e) {
throw new MessagingException(e.getMessage(), e);
}
}
protected void sendmail0(Map<String, Object> mail) throws MessagingException, IOException, TemplateException,
LoginException, RenderingException {
Session session = getSession();
if (javaMailNotAvailable || session == null) {
log.warn("Not sending email since JavaMail is not configured");
return;
}
// Construct a MimeMessage
MimeMessage msg = new MimeMessage(session);
msg.setFrom(new InternetAddress(session.getProperty("mail.from")));
Object to = mail.get("mail.to");
if (!(to instanceof String)) {
log.error("Invalid email recipient: " + to);
return;
}
msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse((String) to, false));
RenderingService rs = Framework.getService(RenderingService.class);
DocumentRenderingContext context = new DocumentRenderingContext();
context.remove("doc");
context.putAll(mail);
context.setDocument((DocumentModel) mail.get("document"));
context.put("Runtime", Framework.getRuntime());
String customSubjectTemplate = (String) mail.get(NotificationConstants.SUBJECT_TEMPLATE_KEY);
if (customSubjectTemplate == null) {
String subjTemplate = (String) mail.get(NotificationConstants.SUBJECT_KEY);
Template templ = new Template("name", new StringReader(subjTemplate), stringCfg);
Writer out = new StringWriter();
templ.process(mail, out);
out.flush();
msg.setSubject(out.toString(), "UTF-8");
} else {
rs.registerEngine(new NotificationsRenderingEngine(customSubjectTemplate));
LoginContext lc = Framework.login();
Collection<RenderingResult> results = rs.process(context);
String subjectMail = "<HTML><P>No parsing Succeded !!!</P></HTML>";
for (RenderingResult result : results) {
subjectMail = (String) result.getOutcome();
}
subjectMail = NotificationServiceHelper.getNotificationService().getEMailSubjectPrefix() + subjectMail;
msg.setSubject(subjectMail, "UTF-8");
lc.logout();
}
msg.setSentDate(new Date());
rs.registerEngine(new NotificationsRenderingEngine((String) mail.get(NotificationConstants.TEMPLATE_KEY)));
LoginContext lc = Framework.login();
Collection<RenderingResult> results = rs.process(context);
String bodyMail = "<HTML><P>No parsing Succedeed !!!</P></HTML>";
for (RenderingResult result : results) {
bodyMail = (String) result.getOutcome();
}
lc.logout();
rs.unregisterEngine("ftl");
msg.setContent(bodyMail, "text/html; charset=utf-8");
// Send the message.
Transport.send(msg);
}
/**
* Gets the session from the JNDI.
*/
private static Session getSession() {
Session session = null;
if (javaMailNotAvailable) {
return null;
}
// First, try to get the session from JNDI, as would be done under J2EE.
try {
NotificationService service = (NotificationService) Framework.getRuntime().getComponent(
NotificationService.NAME);
InitialContext ic = new InitialContext();
session = (Session) ic.lookup(service.getMailSessionJndiName());
} catch (NamingException ex) {
log.warn("Unable to find Java mail API", ex);
javaMailNotAvailable = true;
}
return session;
}
/**
* Instantiate a new session that authenticate given the protocol's properties. Initialize also the default
* transport protocol handler according to the properties.
*
* @since 5.6
*/
public static Session newSession(Properties props) {
Authenticator authenticator = new EmailAuthenticator(props);
Session session = Session.getDefaultInstance(props, authenticator);
String protocol = props.getProperty("mail.transport.protocol");
if (protocol != null && protocol.length() > 0) {
session.setProtocolForAddress("rfc822", protocol);
}
return session;
}
protected Map<String, Object> initMvelBindings(Map<String, Serializable> infos) {
Map<String, Object> map = new HashMap<String, Object>();
map.put("NotificationContext", infos);
return map;
}
/***
* Evaluates a MVEL expression within some context infos accessible on the "NotificationContext" object. Returns
* null if the result is not evaluated to a String
*
* @param expr
* @param ctx
* @return
* @since 5.6
*/
public String evaluateMvelExpresssion(String expr, Map<String, Serializable> ctx) {
// check to see if there is a dynamic MVEL expr
Serializable compiledExpr = MVEL.compileExpression(expr);
Object result = MVEL.executeExpression(compiledExpr, initMvelBindings(ctx));
if (result instanceof String) {
return (String) result;
}
return null;
}
}