I am building a banking application in Java using Spring framework that involved sending email (using SMTP server) but I heard that it's not secure. So how can I make SMTP secure in Java? Is SSL layer and/or HTTPS connection sufficient? Please help.
Thanks.
Instead of making SMTP secure in your java application you need to make cofiguration changes to your SMTP server so that the server will relay mails only from specific ids and ignore others.
Apparently you can use SMTP over SSL with Spring. Here's the sample:
XML Resource
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailS enderImpl">
<property name="host" value="smtp.gmail.com" />
<property name="port" value="465" />
<property name="protocol" value="smtps" />
<property name="username" value="yourAccount#gmail.com"/>
<property name="password" value="yourPassword"/>
<property name="javaMailProperties">
<props>
<prop key="mail.smtps.auth">true</prop>
<prop key="mail.smtps.starttls.enable">true</prop>
<prop key="mail.smtps.debug">true</prop>
</props>
</property>
</bean>
<bean id="mailMessage" class="org.springframework.mail.SimpleMailMessage" >
<property name="from" value="yourAccount#gmail.com" />
<property name="subject" value="Your Subject" />
</bean>
</beans>
Test Class
package test.mail;
import org.springframework.mail.MailException;
import org.springframework.mail.MailSender;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.test.AbstractDependencyInjecti onSpringContextTests;
/**
* MailTest.
* #author jalarcon
*/
public class MailTest extends AbstractDependencyInjectionSpringContextTests {
private MailSender mailSender;
private SimpleMailMessage mailMessage;
/* (non-Javadoc)
* #see org.springframework.test.AbstractSingleSpringConte xtTests#getConfigLocations()
*/
#Override
protected String[] getConfigLocations() {
return new String[] {"/beanDictionary/mail.xml"};
}
public void testSendMail() {
//Create a thread safe "sandbox" of the message
SimpleMailMessage msg = new SimpleMailMessage(this.mailMessage);
msg.setTo("yourAccount#gmail.com");
msg.setText("This is a test");
try{
mailSender.send(msg);
} catch(MailException ex) {
throw new RuntimeException(ex);
}
}
// ---------------------------------------------------------- getters/setters
/**
* #return the mailSender
*/
public MailSender getMailSender() {
return mailSender;
}
/**
* #param mailSender the mailSender to set
*/
public void setMailSender(MailSender mailSender) {
this.mailSender = mailSender;
}
/**
* #return the mailMessage
*/
public SimpleMailMessage getMailMessage() {
return mailMessage;
}
/**
* #param mailMessage the mailMessage to set
*/
public void setMailMessage(SimpleMailMessage mailMessage) {
this.mailMessage = mailMessage;
}
}
Related
I am using Spring JDBC template for establishing the connection with the database. The password is in the encrypted format and want to decrypt it with the help of JDBC template. In order to implement the same, I came to know that I have to override "DriverManagerDataSource" I tried to implement the same but have not succeeded.
<bean id="dataSource"
class="MyclassName">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
public class MyclassName extends DriverManagerDataSource {
#Override
public String getPassword() {
String password = super.getPassword();
//External API decryption call
EncrypterClassName encrypterClassName = new EncrypterClassName();
return encrypterClassName.decrypt(password);
}
}
I know I have to change the <property name="password" value="${jdbc.password}" to call the class I have implemented but not sure How to do the same.
Thank you.
I've written my own ProperyPlaceholderConfigurer which is invoked whenever a variable has to be replaced.
jdbc.password={base64}yourEncryptedSecret
import java.io.IOException;
import sun.misc.BASE64Decoder;
public class PropertyPlaceholderConfigurer
extends org.springframework.beans.factory.config.PropertyPlaceholderConfigurer {
#Override
protected String convertPropertyValue(final String originalValue) {
String cryptString = "{base64}";
if (originalValue.startsWith(cryptString)) {
BASE64Decoder decoder = new BASE64Decoder();
String decodedPassword = null;
try {
decodedPassword = new String(decoder.decodeBuffer(originalValue.substring(cryptString.length())));
} catch (IOException e) {
e.printStackTrace();
}
return decodedPassword;
}
return originalValue;
}
}
I'm new to Spring MVC. I've configured a mail session on Wildfly 8.0 Application server. I am using Spring 3.2. I am using a lookup like this:
<jee:jndi-lookup id="myMailSession"
jndi-name="java:jboss/mail/Email"
expected-type="javax.mail.Session" />
However, I am very much stuck trying to figure out how to do this in Java Config .
How to migrate this xml based JNDI lookup to java configuration?
Finally I got it JNDI Lookup using java configuration.
#Bean
public JavaMailSenderImpl javaMailSenderImpl() {
JavaMailSenderImpl mailSenderImpl = new JavaMailSenderImpl();
mailSenderImpl.setSession(session());
return mailSenderImpl;
}
public Session session(){
JndiTemplate template = new JndiTemplate();
Session session = null;
try {
session = (Session) template.lookup("java:jboss/mail/Email");
} catch (NamingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return session;
}
This above code snippet is equivalent to JNDI Lookup mail xml configuration.
<jee:jndi-lookup id="myMailSession"
jndi-name="java:jboss/mail/Email"
expected-type="javax.mail.Session" />
You can use spring mail to configure you mail sender
<?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:util="http://www.springframework.org/schema/util"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:int-mail="http://www.springframework.org/schema/integration/mail"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/integration
http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-3.2.xsd
http://www.springframework.org/schema/integration/mail
http://www.springframework.org/schema/integration/mail/spring-integration-mail.xsd">
<util:properties id="mailProperties"
location="file:${mf_home}/conf/alertas/mail.properties" />
<!-- Configuracion para velocity template para mensajes -->
<bean id="velocityEngine"
class="org.springframework.ui.velocity.VelocityEngineFactoryBean">
<property name="velocityProperties">
<props>
<prop key="resource.loader">file</prop>
<prop key="file.resource.loader.class">
org.apache.velocity.runtime.resource.loader.FileResourceLoader
</prop>
<prop key="file.resource.loader.path">#{systemProperties['mf_home']}/conf/alertas/templates
</prop>
<prop key="file.resource.loader.cache">true</prop>
</props>
</property>
</bean>
<!-- Configuracion envio de correos -->
<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
<property name="host" value="#{mailProperties['mail.smtp.host']}" />
<property name="username" value="#{mailProperties['mail.smtp.user']}" />
<property name="password" value="#{mailProperties['mail.smtp.password']}" />
<property name="port" value="#{mailProperties['mail.smtp.port']}" />
<property name="javaMailProperties">
<props>
<prop key="mail.smtp.auth">#{mailProperties['mail.smtp.auth']}</prop>
<prop key="mail.smtp.starttls.enable">#{mailProperties['mail.smtp.starttls.enable']}</prop>
</props>
</property>
</bean>
<bean id="mailTransformerBean" class="com.praxis.desvucem.alarms.transformer.MailTransformer" />
</beans>
And you only need import this config context to your main aplication context.
You will also need example code for use it:
package com.praxis.desvucem.alarms.transformer;
import java.util.HashMap;
import java.util.Map;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import javax.inject.Inject;
import org.apache.velocity.app.VelocityEngine;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.integration.Message;
import org.springframework.integration.MessageHeaders;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.ui.velocity.VelocityEngineUtils;
import com.praxis.desvucem.alarms.mensajes.Mensaje;
import com.praxis.desvucem.alarms.domain.MfCContactoAlarma;
public class MailTransformer {
private static Logger log = LoggerFactory.getLogger(MailTransformer.class);
private String templateSufijo = "Email.vm";
/**
* Inyecta propiedades a from.
*/
public #Value("#{mailProperties['mail.smtp.from']}")
String from;
/**
* Inyecta propiedades a sendToUser.
*/
public #Value("#{mailProperties['mail.send.user.default']}")
String sendToUser;
#Inject
private VelocityEngine velocityEngine;
#Inject
private JavaMailSender mailSender;
/**
* Convierte mensajes de tipo Mensaje a MimeMessage y este pueda ser enviado
* por el adaptador de mail.
* #param msj {#link Mensaje} Mensaje Recive el mensaje
* #return MimeMessage {#link MimeMessage} Regresa el mensaje convertido en
* MimeMessage
* #throws Exception al generar MimeMessage en MailTransformer
*/
public MimeMessage mensajeToMimeMessage(Message<?> mensaje) {
MfCContactoAlarma contactoAlarma = (MfCContactoAlarma) mensaje.getPayload();
MessageHeaders header = mensaje.getHeaders();
String mensajeReal = header.get("mensaje").toString();
Map<String, Object> model = new HashMap<String, Object>();
model.put("texto", mensajeReal);
MimeMessage mimeMessage = null;
String destinatarios = contactoAlarma.getConNombre();
if (destinatarios == null) {
log.info("Enviando mensaje por correo al destinatario por defaul {}", sendToUser);
// Se envia al usuario por default
destinatarios = "sendToUser";
}
try {
mimeMessage = armaMensajeConTextoDeTemplate(destinatarios, "Notificación automática VUCEM-MF", model,
"notificacion");
}
catch (Exception e) {
log.error("Error al generar MimeMessage en MailTransformer ", e);
}
return mimeMessage;
}
private MimeMessage armaMensajeConTextoDeTemplate(String emails, String motivo, Map<String, Object> model,
String template) throws MessagingException {
String texto = VelocityEngineUtils.mergeTemplateIntoString(velocityEngine, template + templateSufijo, "utf-8",
model);
if (log.isDebugEnabled()) {
log.debug("Texto del e-mail '" + texto + "'");
}
return armaMensaje(emails, motivo, texto);
}
private MimeMessage armaMensaje(final String emails, final String motivo, final String texto)
throws MessagingException {
MimeMessage mensaje = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(mensaje);
helper.addTo(emails);
helper.setFrom(from);
helper.setSubject(motivo);
boolean isHTML = true;
helper.setText(texto, isHTML);
log.debug("Armando mensaje de correo, Para:[{}], De:[{}], Motivo:[{}] Mensaje:[{}]", emails, from, motivo,
texto);
return mensaje;
}
}
Here I'm using velocity to format message with HTML, this will give you a great look and feel.
You can define a #Configuration class and create a bean like this.
#Bean
public JndiObjectFactoryBean myMailSession() {
JndiObjectFactoryBean bean = new JndiObjectFactoryBean();
bean.setJndiName("java:jboss/mail/Email");
return bean;
}
and in the #Bean where you use the jndi object you have to cast it:
Session mailSession = (Session) myMailSession().getObject();
All - In the Spring 3.0, in the applicationContext.xml .... are we supposed to have the bean property name and the reference value to be the same ? If I give a different value, it returns null object. But on giving the same value, it works. For my project, i am supposed to give different values for them. Kindly help. bye, HS
This works: (same values)
<bean id="MNCWIRAdminBaseAction" class="com.megasoft.wiradmin.web.action.WIRAdminBaseAction">
<property name="cacheDelegate">
<ref bean="cacheDelegate" />
</property>
</bean>
This doesn't work: (different values)
<bean id="MNCWIRAdminBaseAction" class="com.megasoft.wiradmin.web.action.WIRAdminBaseAction">
<property name="cacheDelegate">
<ref bean="MNCCacheDelegate" />
</property>
</bean>
bye, HS
My Full Code here:
WIRAdminBaseAction.java ---> my base action
AuthenticateAction.java ---> my java file that calls the bean here
applicationContext.xml --> system's applicationcontext file
applicationContext_MNC.xml ---> my applicationContext for a specific company ... this is getting loaded by my java file, which gets invoked by the web.xml file.
CacheDelegate.java
StatusDBDAO.java
PreXMLWebApplicationContext.java ----> loads my applicationContext file for the specific company.
****** applicationContext.xml ******
<?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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd ">
<bean name="exceptionHandler" class="com.megasoft.wir.eStatement.web.interceptor.WIRExceptionHandlerInterceptor"/>
<bean name="security" class="com.megasoft.wir.eStatement.web.interceptor.SecurityInterceptor"/>
<bean name="permission" class="com.megasoft.wir.eStatement.web.interceptor.PermissionInterceptor"/>
<!-- AutoProxies -->
<bean name="loggingAutoProxy" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="interceptorNames">
<list>
<value>base</value>
<value>exceptionHandler</value>
<value>security</value>
<value>permission</value>
</list>
</property>
</bean>
</beans>
****** applicationContext_MNC.xml ******
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="MNCWIRAdminBaseAction" class="com.megasoft.wiradmin.web.action.WIRAdminBaseAction">
<property name="cacheDelegate">
<ref bean="MNCCacheDelegate" />
</property>
</bean>
<bean id="MNCCacheDelegate" class="com.megasoft.wiradmin.delegate.CacheDelegate" >
<property name="statusDBDAO"><ref bean="MNCStatusDBDAO" /></property>
</bean>
<bean id="MNCStatusDBDAO" class="com.megasoft.wiradmin.dao.StatusDBDAO">
<property name="dataSource">
<ref bean="MNCAdminDataSource" />
</property>
</bean>
<!-- database configuration from property file -->
<bean id="MNCAdminDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close" lazy-init="default" autowire="default" dependency-check="default">
<property name="driverClass" value="${jdbc.driver}" ></property>
<property name="jdbcUrl" value="${admin.jdbc.url}" ></property>
<property name="user" value="${admin.jdbc.user}" ></property>
<property name="password" value="${admin.jdbc.password}" ></property>
<property name="initialPoolSize" value="3" ></property>
<property name="minPoolSize" value="3" ></property>
<property name="maxPoolSize" value="25" ></property>
<property name="acquireIncrement" value="1" ></property>
<property name="acquireRetryDelay" value="1000" ></property>
<property name="debugUnreturnedConnectionStackTraces" value="true" ></property>
<property name="maxIdleTime" value="300" ></property>
<property name="unreturnedConnectionTimeout" value="300000" ></property>
<property name="preferredTestQuery" value="SELECT COUNT(*) FROM LOCALE_CODE" ></property>
<property name="checkoutTimeout" value="300000" ></property>
<property name="idleConnectionTestPeriod" value="600000" ></property>
</bean>
<!-- this bean is set to map the constants which needs to be configured as per
the environment to the java constants file -->
<bean id="envConstantsConfigbean" class="com.megasoft.wiradmin.util.constants.Environm entConstantsSetter">
<property name="loginUrl" value="${login.url}"/>
<property name="logoutIR" value="${logout.from.image.retrieval}"/>
<property name="adminModuleUrl" value="${admin.url}"/>
<property name="adminUrlSym" value="${admin.url.sym}"/>
<property name="envProperty" value="${env.property}"/>
</bean>
</beans>
****** AuthenticateAction.java ******
package com.megasoft.wiradmin.web.action;
import java.net.UnknownHostException;
import java.sql.SQLException;
import org.bouncycastle.crypto.CryptoException;
import org.springframework.context.ApplicationContext;
import org.springframework.dao.DataAccessException;
import org.springframework.web.context.support.WebApplica tionContextUtils;
import com.megasoft.wiradmin.delegate.ICacheDelegate;
public class AuthenticateAction extends WIRAdminBaseAction {
private static final long serialVersionUID = 1L;
public String authenticate() throws UnknownHostException, CryptoException,
DataAccessException, SQLException{
/** This way of calling works...... This is not encouraged, as we should not use applicationContext always **/
ApplicationContext applicationContext = WebApplicationContextUtils.getWebApplicationContex t(getServletRequest().getSession().getServletConte xt());
ICacheDelegate cacheAction = (ICacheDelegate) applicationContext.getBean("MNCCacheDelegate");
/** The below way of calling does NOT work .... returns null value.... Please help...
* I assume that, since I have extended the WIRAdminBaseAction, i should be able to call the getCacheDelegate directly
* and it should return my cacheDelegate object ...
* Again, Please note.....if I change my applicationContext_MNC.xml as below, the below way of calling works fine...
* but, i don't want to change my applicationContext_MNC.xml as below, due to some necessity.
*
<bean id="MNCWIRAdminBaseAction" class="com.megasoft.wiradmin.web.action.WIRAdminBaseAction">
<property name="cacheDelegate">
<ref bean="cacheDelegate" />
</property>
</bean>
*
<bean id="cacheDelegate" class="com.megasoft.wiradmin.delegate.CacheDelegate" >
<property name="statusDBDAO"><ref bean="MNCStatusDBDAO" /></property>
</bean>
*
... is it that the name and bean should have the same value.... ??? No Need to be.....Am i right ? Please advise.
*
* **/
getCacheDelegate().getActorAction(1); // this way of calling doesn't work and returns null value. please help.
return "success";
}
}
****** WIRAdminBaseAction.java ******
package com.megasoft.wiradmin.web.action;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts2.interceptor.ParameterAware;
import org.apache.struts2.interceptor.SessionAware;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.Preparable;
import com.opensymphony.xwork2.config.entities.Parameteri zable;
import com.megasoft.wiradmin.delegate.ICacheDelegate;
public class WIRAdminBaseAction extends ActionSupport implements Preparable, ParameterAware, Parameterizable, SessionAware,RequestAware {
private HttpServletRequest request;
private static final long serialVersionUID = 1L;
private HttpServletResponse response;
private ICacheDelegate cacheDelegate;
private Map session;
private Map<String, String> params;
private Map parameters;
public void prepare() throws Exception {
}
public String execute() throws Exception {
return SUCCESS;
}
public void setServletRequest(HttpServletRequest request) {
this.request = request;
}
public HttpServletRequest getServletRequest() {
return this.request;
}
public void setServletResponse(HttpServletResponse response) {
this.response = response;
}
public HttpServletResponse getServletResponse() {
return this.response;
}
public ICacheDelegate getCacheDelegate() {
return cacheDelegate;
}
public void setCacheDelegate(ICacheDelegate cacheDelegate) {
this.cacheDelegate = cacheDelegate;
}
public void addParam(final String key, final String value) {
this.params.put(key, value);
}
public Map getParams() {
return params;
}
public void setParams(final Map<String, String> params) {
this.params = params;
}
public Map getSession() {
return this.session;
}
public void setSession(final Map session) {
this.session = session;
}
public void setParameters(final Map param) {
this.parameters = param;
}
}
PreXMLWebApplicationContext.java **
package com.megasoft.wiradmin.util;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.web.context.support.XmlWebApplicationContext;
public class PreXMLWebApplicationContext extends XmlWebApplicationContext {
/**
* This initializes the Logger.
*/
private static Log logger = LogFactory.getLog(PreXMLWebApplicationContext.class);
protected String[] getDefaultConfigLocations() {
String environment = System.getProperty("envProperty");
String webirConfig = System.getProperty("webirConfig");
String fi = System.getProperty("FI");
String preHostConfiguration =null;
logger.info("The environment is "+environment);
logger.info("The webirConfig is "+webirConfig);
logger.info("The fi is "+fi);
if(environment != null && webirConfig != null && fi != null) {
preHostConfiguration = DEFAULT_CONFIG_LOCATION_PREFIX +
"classes/applicationContext" + "_" + fi.toUpperCase() +
DEFAULT_CONFIG_LOCATION_SUFFIX;
}
return new String[]{DEFAULT_CONFIG_LOCATION, preHostConfiguration};
}
/**
* This is close API.
*
* #see org.springframework.context.support.AbstractApplicationContext
* #close()
*/
public void close() {
this.doClose();
logger.info("Login-->into the closed");
}
}
<property name="userDelegate" ref="userDelegate" />
name is the field name in your class. When name is userDelegate, it means that WIRAdminBaseAction has a field named userDelegate (and probably a setter setUserDelegate())
ref is the bean name you want to set this field to. In your example, you should have another bean, named userDelegate or bmoUserDelegate which should be set as userDelegate in WIRAdminBaseAction.
So if you want to use the second configuration:
You just need to create a bean with id bmoUserDelegate:
<bean id="bmoUserDelegate" class="mypackage.BmoUserDelegateClass"/>
I would just like to ask how can i setup a simple mail server and be able to send an email. Im using apache tomcat 6.0 as my localhost server and spring framework+jsp as well. I'm quite new on this. So if someone can give a nice tutorial, it will be of great help. thanks
Below is how you would get the spring configuration. probably applicationContext-mail.xml. Import that into applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"autowire="byName">
default-autowire="byName">
<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
<property name="host" value="${mail.host}" />
<property name="port" value="${mail.port}" />
<property name="username" value="${mail.username}" />
<property name="password" value="${mail.password}" />
</bean>
<bean id="freemarkerConfiguration"
class="org.springframework.ui.freemarker.FreeMarkerConfigurationFactoryBean">
<property name="templateLoaderPath" value="/WEB-INF/templates" />
</bean>
<!-- KINDLY MAINTAIN ALPHABETICAL ORDER THIS LINE ONWARDS -->
<bean id="notificationService" class="com.isavera.service.NotificationServiceImpl"
scope="prototype">
<property name="mailSender" ref="mailSender" />
<property name="freemarkerConfiguration" ref="freemarkerConfiguration" />
<property name="freemarkerTemplate" value="accountInformation.ftl" />
<property name="fromAddress" value="info#apnagenie.com" />
<property name="subject" value="Your account information" />
</bean>
Below is the NotificationServiceImpl
public class NotificationServiceImpl implements NotificationService, Runnable {
private boolean asynchronous = true;
private JavaMailSender mailSender;
private Configuration freemarkerConfiguration;
private String freemarkerTemplate;
private Map<String, Object> attributes;
private String deliveryAddress;
private String[] deliveryAddresses;
private String fromAddress;
private String subject;
private SimpleMailMessage message;
private MimeMessage mimeMessage;
public void deliver() {
message = new SimpleMailMessage();
if (getDeliveryAddresses() == null) {
message.setTo(getDeliveryAddress());
} else {
message.setTo(getDeliveryAddresses());
}
message.setSubject(subject);
message.setFrom(fromAddress);
// Merge the model into the template
final String result;
try {
result = FreeMarkerTemplateUtils.processTemplateIntoString(freemarkerConfiguration.getTemplate(appendApplicationName(freemarkerTemplate)), attributes);
message.setText(result);
if (asynchronous) {
Thread emailThread = new Thread(this);
emailThread.start();
} else {
run();
}
} catch (IOException e) {
e.printStackTrace();
} catch (TemplateException e) {
e.printStackTrace();
}
}
}
I have updated my libraries, and now e-mails are sent without subject. I don't know where this happened...
Mail API is 1.4.3., Spring 2.5.6. and Spring Integration Mail 1.0.3.RELEASE.
<!-- Definitions for SMTP server -->
<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
<property name="host" value="${mail.host}" />
<property name="username" value="${mail.username}" />
<property name="password" value="${mail.password}" />
</bean>
<bean id="adminMailTemplate" class="org.springframework.mail.SimpleMailMessage" >
<property name="from" value="${mail.admin.from}" />
<property name="to" value="${mail.admin.to}" />
<property name="cc">
<list>
<value>${mail.admin.cc1}</value>
</list>
</property>
</bean>
<!-- Mail service definition -->
<bean id="mailService" class="net.bbb.core.service.impl.MailServiceImpl">
<property name="sender" ref="mailSender"/>
<property name="mail" ref="adminMailTemplate"/>
</bean>
And properties mail.host,mail.username,mail.password,mail.admin.from,mail.admin.to,
mail.admin.cc1.
Java class:
/** The sender. */
private MailSender sender;
/** The mail. */
private SimpleMailMessage mail;
public void sendMail() {
this.mail.setSubject("Subject");
this.mail.setText("msg body");
try {
getSender().send(this.mail);
} catch (MailException e) {
log.error("Error sending mail!",e);
}
}
public SimpleMailMessage getMail() {
return this.mail;
}
public void setMail(SimpleMailMessage mail) {
this.mail = mail;
}
public MailSender getSender() {
return this.sender;
}
public void setSender(MailSender mailSender1) {
this.sender = mailSender1;
}
Everything worked before, I am wondering if there may be any conflicts with new libraries.
Finally - I had the time to resolve this.
In pom.xml, I have added java mail dependency and remove exclusion for geronimo javamail in apache axis transport http dependency.
I expect it's something to do with the way that you're injecting a singleton SimpleMailMessage into your bean. This is not thread-safe, since every call to your sendMail method will be using the same underlying SimpleMailmessage object. It's quite possible that some implementation change in the new libraries now means this is broken.
SimpleMailMessage has a copy constructor, so you should do it like this:
<bean id="mailService" class="net.bbb.core.service.impl.MailServiceImpl">
<property name="sender" ref="mailSender"/>
<property name="template" ref="adminMailTemplate"/>
</bean>
and
private SimpleMailMessage template;
public void setTemplate(SimpleMailMessage template) {
this.template = template;
}
public void sendMail() {
SimpleMailMessage message = new SimpleMailMessage(template);
message.setSubject("Subject");
message.setText("msg body");
try {
getSender().send(message);
} catch (MailException e) {
log.error("Error sending mail!",e);
}
}