We’re going to explore all flowing from controller to the freemarker html template to send an email.
package com.jos.dem.jmailer.controller
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Controller
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.ResponseBody
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.http.ResponseEntity
import org.springframework.http.HttpStatus
import com.google.gson.Gson
import static org.springframework.web.bind.annotation.RequestMethod.GET
import static org.springframework.web.bind.annotation.RequestMethod.POST
import com.jos.dem.jmailer.service.EmailerService
import com.jos.dem.jmailer.command.MessageCommand
import com.jos.dem.jmailer.command.MessageType
import org.apache.commons.logging.Log
import org.apache.commons.logging.LogFactory
@Controller
class EmailerController {
@Autowired
EmailerService emailerService
Log log = LogFactory.getLog(this.class)
@ResponseBody
ResponseEntity<String> message(@RequestBody String json) {
MessageCommand command = new Gson().fromJson(json, MessageCommand.class)
log.info "Sending contact email: ${command.email}"
command.type = MessageType.MESSAGE
emailerService.sendEmail(command)
new ResponseEntity<String>("OK", HttpStatus.OK)
}
}
This controller receives an json as parameter and using Gson library parser transform it to a command, we could send a request from command line like this:
curl -H "Content-Type: application/json" -X POST -d '{"email":"joseluis.delacruz@gmail.com","message":"message"}' 'http://localhost:8080/jmailer/message'
The emailService is responsible to send an email based in a command, let’s see its definition
package com.jos.dem.jmailer.service
import com.jos.dem.jmailer.command.MessageCommand
interface EmailerService {
def sendEmail(MessageCommand command)
}
First a interface definition to decouple controller and service relationship, then a definition.
package com.jos.dem.jmailer.service.impl
import org.springframework.stereotype.Service
import org.springframework.beans.factory.annotation.Autowired
import com.jos.dem.jmailer.service.MessageService
import com.jos.dem.jmailer.service.EmailerService
import com.jos.dem.jmailer.command.MessageCommand
import com.jos.dem.jmailer.exception.EmailerException
import org.apache.commons.logging.Log
import org.apache.commons.logging.LogFactory
@Service
class EmailerServiceImpl implements EmailerService {
@Autowired
MessageService messageService
Log log = LogFactory.getLog(this.class)
def sendEmail(MessageCommand command){
log.info 'Sending email ${command.email}'
messageService.message(command)
}
}
Email service delegates to the messageService to send the email
package com.jos.dem.jmailer.service
import com.jos.dem.jmailer.command.MessageCommand
interface MessageService {
void message(final MessageCommand command)
}
Message service implementation
package com.jos.dem.jmailer.service.impl
import javax.jms.JMSException
import javax.jms.Message
import javax.jms.ObjectMessage
import javax.jms.Session
import javax.jms.Destination
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.jms.core.JmsTemplate
import org.springframework.jms.core.MessageCreator
import org.springframework.stereotype.Service
import com.jos.dem.jmailer.service.MessageService
import com.jos.dem.jmailer.command.MessageCommand
import org.apache.commons.logging.Log
import org.apache.commons.logging.LogFactory
@Service
class MessageServiceImpl implements MessageService {
@Autowired
JmsTemplate template
@Autowired
Destination destination
Log log = LogFactory.getLog(getClass())
void message(final MessageCommand command) {
log.info "CALLING Message"
template.send(destination, new MessageCreator() {
Message createMessage(Session session) throws JMSException {
ObjectMessage message = session.createObjectMessage()
message.setObject(command)
return message
}
})
}
}
In our message service implementation we create an message and using an JMS template we deliver our message to the destination.
The receiver should be an MessageListener implementation
package com.jos.dem.jmailer.messengine
import javax.jms.Message
import javax.jms.MessageListener
import javax.jms.ObjectMessage
import org.springframework.stereotype.Service
import org.springframework.beans.factory.annotation.Autowired
import com.jos.dem.jmailer.service.NotificationService
import org.apache.commons.logging.Log
import org.apache.commons.logging.LogFactory
@Service
class JmsMessageListener implements MessageListener {
@Autowired
NotificationService notificationService
Log log = LogFactory.getLog(getClass())
void onMessage(Message message) {
log.info 'Email message received'
Object command = ((ObjectMessage) message).getObject()
notificationService.sendNotification(command)
}
}
JmsMessageListener receives the email message and from this side uses and notificationService to transform it to an email
package com.jos.dem.jmailer.service
import com.jos.dem.jmailer.command.MessageCommand
interface NotificationService {
void sendNotification(MessageCommand command)
}
NotificationService implementation
package com.jos.dem.jmailer.service.impl
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.annotation.Qualifier
import org.springframework.stereotype.Service
import com.jos.dem.jmailer.integration.MailService
import com.jos.dem.jmailer.service.NotificationService
import com.jos.dem.jmailer.command.MessageCommand
import com.jos.dem.jmailer.constant.ApplicationConstants
import org.apache.commons.logging.Log
import org.apache.commons.logging.LogFactory
@Service
class NotificationServiceImpl implements NotificationService {
@Autowired
MailService mailService
@Autowired
Properties properties
private Log log = LogFactory.getLog(getClass())
@Override
void sendNotification(MessageCommand messageCommand) {
def (subject, templateName) = obtainSubjectAndResourceToSendNotification(messageCommand)
def data = [email:messageCommand.email, subject:subject, templateName:templateName]
mailService.sendMailWithTemplate(data, messageCommand.properties, data.templateName)
}
def obtainSubjectAndResourceToSendNotification(MessageCommand messageCommand){
String templateKey = "${messageCommand.type.toString()}_PATH"
String subjectKey = "${messageCommand.type.toString()}_SUBJECT"
String templateName = properties.getProperty(templateKey)
String subject = properties.getProperty(subjectKey)
log.info("Sending email with subject: " + subject)
[subject, templateName]
}
}
The responsibility from this pice of code is to extract subject an a freemarker template name from a properties file and then send those parameters to the mail service
package com.jos.dem.jmailer.integration
interface MailService {
void sendMailWithTemplate(Map values, Map model, String template)
}
Mail service implementation
package com.jos.dem.jmailer.integration.impl
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.mail.javamail.JavaMailSender
import org.springframework.mail.javamail.MimeMessageHelper
import org.springframework.mail.javamail.MimeMessagePreparator
import org.springframework.stereotype.Service
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils
import com.jos.dem.jmailer.integration.MailService
import freemarker.template.Configuration
import freemarker.template.Template
import javax.mail.internet.MimeMessage
import org.apache.commons.logging.Log
import org.apache.commons.logging.LogFactory
@Service
class MailServiceImpl implements MailService {
@Autowired
Configuration configuration
@Autowired
JavaMailSender javaMailSender
Log log = LogFactory.getLog(getClass())
void sendMailWithTemplate(final Map values, final Map model, final String template) {
MimeMessagePreparator preparator = new MimeMessagePreparator() {
void prepare(MimeMessage mimeMessage) throws Exception {
MimeMessageHelper message = new MimeMessageHelper(mimeMessage, true)
Template myTemplate = configuration.getTemplate(template)
message.setTo(values.email)
message.setSubject(values.subject)
String text = FreeMarkerTemplateUtils.processTemplateIntoString(myTemplate, model)
message.setText(text, true)
}
}
this.javaMailSender.send(preparator)
}
}
Mail service gets a template from a freemarker configuration, and prepare the email.
To get ths work, we need an xml context who defines javaMail parameters and freemarker configuration, as you can see we define in freemarker/mail path our templates
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:component-scan base-package="com.jos.dem.jmailer.integration"/>
<context:property-placeholder location="classpath:config/emailer.properties" />
<bean id="javaMailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
<property name="host" value="smtp.gmail.com" />
<property name="port" value="465" />
<property name="username" value="${email.sender}" />
<property name="password" value="${email.password}" />
<property name="javaMailProperties">
<props>
<prop key="mail.smtp.auth">true</prop>
<prop key="mail.smtp.socketFactory.port">465</prop>
<prop key="mail.smtp.socketFactory.class">javax.net.ssl.SSLSocketFactory</prop>
<prop key="mail.smtp.socketFactory.fallback">false</prop>
</props>
</property>
</bean>
<bean id="freemarkerConfiguration"
class="org.springframework.ui.freemarker.FreeMarkerConfigurationFactoryBean">
<property name="templateLoaderPath" value="classpath:/freemarker/mail/" />
</bean>
</beans>
Our message template look like this
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Notificación</title>
</head>
<body>
<h1>Mensaje</h1>
<h3>Administrator</h3>
<hr>
<p>Message: ${message}</p>
</body>
</html>
FreeMarker will step in and transform the template on-the-fly to plain HTML by replacing the ${message} with our command message information.
To download the project
git clone https://github.com/josdem/jmailer-bootstrap.git
git fetch
git checkout feature/java-mail