Hello,
After my post about the Fake SMTP Server/SMTP4DEV, today, I would present a solution for the sending of email in your java applications.
So, we will consider sending emails using the Spring framework.
Indeed, Spring provides a number of utility classes that facilitate the integration of your applications with the JavaMail API, especially the classes org.springframework.mail.javamail.JavaMailSenderImpl and org.springframework.mail.javamail.MimeMessageHelper.
To use Spring to integrate JavaMail in your applications, we have obviously the jars spring-2.5.5.jar, mail-1.3.2.jar, junit-4.1.jar, commons-beanutils-1.6.jar, commons-io-1.4.jar, commons-logging-1.1.1.jar.
To check the mail sent by our solution, we will use Fake SMTP Server or the SMTP4DEV software as descried here.
Important note: Some classes in the mail-1.3.2.jar exist also in the library geronimo-javamail_1.4_spec-1.3.jar, so, in order to avoid the conflict, remove the geronimo-javamail library from your project using this solution based on mail-1.3.2.jar.
Configuration
The mail sending is implemented in a main static class named MailSender with the support of message content through a configuration templates. This class is configured in Spring context file spring-mail-config.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans ...>
<!--
| Factory bean created in order to use a unique instance of "MailSender" in:
| + MailSender mailSender = (MailSender) ctx.getBean("mailSender");
| OR
| + MailSender.getInstance().sendMail(emails, templateName, mappingData);
-->
<bean id="mailSenderFactoryBean" class="com.ho.test.mail.ex1.sending.MailSenderFactoryBean"/>
<!--
| This bean is used to:
| + build the message from template;
| + mapping datas to the template;
| + send email;
-->
<bean id="mailSender" class="com.ho.test.mail.ex1.sending.MailSender"
factory-bean="mailSenderFactoryBean"
factory-method="createInstance">
</bean>
</beans>
… this Spring context will be accessible via the singleton CommonContext:
public class CommonContext {
private static CommonContext currentInstance = null;
/** The ctx. */
private ApplicationContext ctx;
private CommonContext() {
//load spring bean
ctx = new ClassPathXmlApplicationContext(new String[] {"spring-mail-config.xml"});
}
public static synchronized CommonContext getInstance() {
if (currentInstance == null) {
currentInstance = new CommonContext();
}
return currentInstance;
}
public ApplicationContext getCtx() {
return ctx;
}
public void setCtx(ApplicationContext ctx) {
this.ctx = ctx;
}
}
…so, the Spring context contains a factory bean named MailSenderFactoryBean needed only in order to use an unique instance of the MailSender in:
MailSender mailSender = (MailSender) ctx.getBean("mailSender");
//OR
MailSender.getInstance().sendMail(emails, templateName, mappingData);
public class MailSenderFactoryBean{
public MailSender createInstance() throws Exception {
MailSender mailSender = MailSender.getInstance();
return mailSender;
}
}
…., here, a part of the main class MailSender which allows:
- the mail sending with the loading of mail session via the class MailSessionLoader,
- the formating of message due to an internal class TemplateMailBean building the message from template and its corresponding datas in the ${parameterName} format,
public class MailSender {
private static MailSender singleton = null;
private MailSender() {}
public static synchronized MailSender getInstance() {
if (singleton == null){
singleton = new MailSender();
}
return singleton;
}
@SuppressWarnings("unchecked")
public synchronized void sendMail(String smtpMailFrom, String[] recipientsEmailTo, String[] recipientsEmailCc, String[] recipientsEmailBcc, String templateName, Map<String, String> mappingData, Map<String, InputStreamSource> attachments) throws Throwable{
System.out.println("sendMail()");
// MAIL SESSION
/*javax.mail.Session mailSession = null;
{
Hashtable<String,String> env = new Hashtable<String,String> ();
env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory");
mailSession = (javax.mail.Session) new InitialContext(env).lookup("java:comp/env/mail/Session");
}*/
//
MailSessionLoader loader=new MailSessionLoader();
Session mailSession=loader.loadJavaMailSession();
// Build the message
MimeMessage mailMsg = new MimeMessage(mailSession);
MimeMessageHelper helper = new MimeMessageHelper(mailMsg, true);
// Set the mail sender
{
if(smtpMailFrom == null){
smtpMailFrom = SMTPConstant.SMTP_SENDER_EMAIL;
}
helper.setFrom(new InternetAddress(smtpMailFrom));
} // end-block
// Set the recipient To
{
if(recipientsEmailTo!=null){
for (int i = 0; i < recipientsEmailTo.length; i++) {
if(recipientsEmailTo[i]!=null && !"".equalsIgnoreCase(recipientsEmailTo[i].trim())){
helper.addTo(new InternetAddress(recipientsEmailTo[i].trim()));
}
}
}
} // end-block
....
TemplateMailBean bean=null;
{
bean = new TemplateMailBean(templateName, mappingData);
}
....
}
...
}
…this bean TemplateMailBean uses the templates configured in constants of the class SMTPConstant:
TEMPLATE_MAIL_GENERIC
subject=${subject}
body=${htmlBody}
footer=${footer}
TEMPLATE_MAIL_SPECIFIC
subject=JAVABLOG: Error for post ${referencePOST}
body=An error is occured during the treatment of system with the following message: ${htmlMessage}
footer=This is an automatically generated e-mail sent by JAVABLOG, please don’t reply.
Simple Example
Below, a simple example of mail sending using the generic template TEMPLATE_MAIL_GENERIC:
// TemplateName
String templateName = "TEMPLATE_MAIL_GENERIC";
// Recepients To
String[] recipientsEmailTo = new String[]{"huseyin.ozveren@javablog.fr", "ozveren@java.lu"};
// Data to be used
Map<String, String> mappingData = new HashMap<String, String>();
mappingData.put("subject","JavaBlog.fr: - Generic - Error Notification for the post 123465798012546547");
mappingData.put("htmlBody"," - Generic - An error is occured during the treatment of system with the following message:<br/> <a href='http://www.javablog.fr'>clic here</a> to access to JAVABLOG.FR");
mappingData.put("footer","- Generic - This is an automatically generated e-mail sent by JAVABLOG, please don't reply.");
//
MailSender.getInstance().sendMail(recipientsEmailTo, templateName, mappingData);
… traces in the output would be:
sendMail()
MailSessionLoader.loadJavaMailSession()
templateName=TEMPLATE_MAIL_GENERIC - mappingData={footer=- Generic - This is an automatically generated e-mail sent by JAVABLOG, please don't reply., subject=JavaBlog.fr: - Generic - Error Notification for the post 123465798012546547, htmlBody= - Generic - An error is occured during the treatment of system with the following message:<br/> <a href='http://www.javablog.fr'>clic here</a> to access to JAVABLOG.FR}
prop {body=- Generic - An error is occured during the treatment of system with the following message:<br/> <a href='http://www.javablog.fr'>clic here</a> to access to JAVABLOG.FR, subject=JavaBlog.fr: - Generic - Error Notification for the post 123465798012546547, footer=- Generic - This is an automatically generated e-mail sent by JAVABLOG, please don't reply.}
INFO : MAILSENT : Sat Aug 11 01:28:55 CEST 2012 : MailSender : subject : JavaBlog.fr: - Generic - Error Notification for the post 123465798012546547 recipients : huseyin.ozveren@javablog.fr;ozveren@java.lu;
Advanced Tests
The project in attachement contains a JUNIT TestMailSender with two concrets cases:
- an example of mail sending using the generic template TEMPLATE_MAIL_SPECIFIC containing the parameters referencePOST and htmlMessage:
// TemplateName String templateName = "TEMPLATE_MAIL_SPECIFIC"; // Recepients To String[] recipientsEmailTo = new String[]{"huseyin.ozveren@javablog.fr", "ozveren@java.lu"}; // Data to be used Map<String, String> mappingData = new HashMap<String, String>(); mappingData.put("referencePOST", "123456"); mappingData.put("htmlMessage", "..... message error...... "); MailSender.getInstance().sendMail(recipientsEmailTo, templateName, mappingData);… traces in the output would be:
sendMail() MailSessionLoader.loadJavaMailSession() templateName=TEMPLATE_MAIL_SPECIFIC - mappingData={htmlMessage=..... message error...... , referencePOST=123456} prop {body=An error is occured during the treatment of system with the following message: ..... message error...... , subject=JAVABLOG: Error for post 123456, footer=This is an automatically generated e-mail sent by JAVABLOG, please don't reply.} INFO : MAILSENT : Sat Aug 11 01:28:56 CEST 2012 : MailSender : subject : JAVABLOG: Error for post 123456 recipients : huseyin.ozveren@javablog.fr;ozveren@java.lu; - an example of mail sending using the generic template TEMPLATE_MAIL_GENERIC, with recepients in To, CC and with 2 text files in attachement:
// TemplateName String templateName = "TEMPLATE_MAIL_GENERIC"; // From String smtpMailFrom = "contact@java.lu"; // Recepients To String[] recipientsEmailTo = new String[]{"huseyin.ozveren@javablog.fr", "ozveren@java.lu"}; // Recepients Cc String[] recipientsEmailCc = new String[]{"huseyinCC@javablog.fr", "ozverenCC@java.lu"}; // Data to be used Map<String, String> mappingData = new HashMap<String, String>(); mappingData.put("subject","JavaBlog.fr: - Generic - Error Notification for the post 123465798012546547"); mappingData.put("htmlBody"," - Generic - An error is occured during the treatment of system with the following message:<br/> <a href='http://www.javablog.fr'>clic here</a> to access to JAVABLOG.FR"); mappingData.put("footer","- Generic - This is an automatically generated e-mail sent by JAVABLOG, please don't reply."); // Attachments Map<String, InputStreamSource> attachments = new HashMap<String, InputStreamSource>(); { // Creation of a file1 { File attachmentFile1 = null; attachmentFile1 = File.createTempFile("attachment1", ".txt"); attachmentFile1.deleteOnExit(); FileOutputStream flout = new FileOutputStream(attachmentFile1); flout.write("text JAVABLOG.FR JAVA.LU text ".getBytes("UTF-8")); flout.close(); InputStreamSource iss1 = null; iss1 = new InputStreamResource(new FileInputStream(attachmentFile1)); attachments.put("MyAttachment1.txt", iss1); } // Creation of a file2 { File attachmentFile2 = null; attachmentFile2 = File.createTempFile("attachment2", ".txt"); attachmentFile2.deleteOnExit(); FileOutputStream flout = new FileOutputStream(attachmentFile2); flout.write("text JAVABLOG.FR JAVA.LU text ".getBytes("UTF-8")); flout.close(); InputStreamSource iss2 = null; iss2 = new InputStreamResource(new FileInputStream(attachmentFile2)); attachments.put("MyAttachment2.txt", iss2); } } MailSender.getInstance().sendMail(smtpMailFrom, recipientsEmailTo, recipientsEmailCc, null, templateName, mappingData, attachments);… traces in the output would be:
sendMail() MailSessionLoader.loadJavaMailSession() templateName=TEMPLATE_MAIL_GENERIC - mappingData={footer=- Generic - This is an automatically generated e-mail sent by JAVABLOG, please don't reply., subject=JavaBlog.fr: - Generic - Error Notification for the post 123465798012546547, htmlBody= - Generic - An error is occured during the treatment of system with the following message:<br/> <a href='http://www.javablog.fr'>clic here</a> to access to JAVABLOG.FR} prop {body=- Generic - An error is occured during the treatment of system with the following message:<br/> <a href='http://www.javablog.fr'>clic here</a> to access to JAVABLOG.FR, subject=JavaBlog.fr: - Generic - Error Notification for the post 123465798012546547, footer=- Generic - This is an automatically generated e-mail sent by JAVABLOG, please don't reply.} INFO : MAILSENT : Sat Aug 11 01:28:56 CEST 2012 : MailSender : subject : JavaBlog.fr: - Generic - Error Notification for the post 123465798012546547 recipients : huseyin.ozveren@javablog.fr;ozveren@java.lu;huseyinCC@javablog.fr;ozverenCC@java.lu;
For more informations, you could contact me.
Download: test_mail1.zip
Best regards,
Huseyin OZVEREN




