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