Thursday 8 April 2010

email: spring + velocity

One of the best ways to send e-mails is with spring and velocity template. With this technique sending an e-mail is as easy as make a jsp.

In this sample I'm integrating the spring & velocity with struts2 and portlets, but could be extrapolated to any other environment.

The recipe consists of:
- applicationContextBeans.xml -> the sprig config file (the glue)
- registrarse.vm -> a velocity template of our e-mail
- EmailService.java & EmailServiceImpl.java -> the classes to apply the data to the template and send the e-mail. These classes will be the same for all the e-mails, so could be in a separate jar.
- RegistrarseAction.java -> the struts2 action

-applicationContextBeans.xml:
<bean id="emaiInformacionlService" class="es.project.miGestion.administracionDatos.service.EmailServiceImpl" scope="prototype">
        <property name="velocityEngine" ref="velocityEngine"></property>
        <property name="velocityTpl" value="es/project/velocity/solicitudInformacion.vm"></property>
            <property name="inlineFiles">   
         <map>              
             <entry>  
                 <key>  
                     <value>id001</value>  
                 </key>  
                 <value>classpath:es/project/velocity/logoproject.png</value>  
             </entry>  
         </map>  
       </property>  
    </bean>
    <bean id="emailRegistrarseService" class="es.project.miGestion.administracionDatos.service.EmailServiceImpl" scope="prototype">
        <property name="velocityEngine" ref="velocityEngine"></property>
        <property name="velocityTpl" value="es/project/velocity/registrarse.vm"></property>
        <property name="inlineFiles">   
         <map>              
             <entry>  
                 <key>  
                     <value>id001</value>  
                 </key>  
                 <value>classpath:es/project/velocity/logoproject.png</value>  
             </entry>  
         </map>  
       </property>  
    </bean>

- registrarse.vm:
<div id="logo">
        <p align="right"><img src="cid:id001" /></p>
    </div>
    <div id="header">
        <font size="2" style="font-family: Arial; color: rgb(51, 90, 143);">
            A la Atenci&oacute;n del Servicio de Atenci&oacute;n Telef&oacute;nica
            <br><br>
            Cliente registrado en el formulario de la web. 
            #set ($bar = "cliente")
            #if (${cliente} == $bar)
                Ya es cliente de  project y desea que un comercial se encarge de darle de alta en la Web de  project:
            #else
                No es cliente de  project y desea que un comercial se encarge de darle de alta en la Web de  project:
            #end
        </font>
    </div>
    <br>
    <div id="content">
        <font size="2" style="font-family: Arial; color: rgb(51, 90, 143);">
            <table class="width100" border="0" cellspacing="0" cellpadding="0">    
                <tr>
                    <td style="font-size: 9pt; font-family: Arial; color: rgb(51, 90, 143);" width="110">Nombre</td>
                    <td style="font-size: 9pt; font-family: Arial; color: rgb(51, 90, 143);" >${nombre} ${apellidos}</td>
                </tr>
                <tr>
                    <td style="font-size: 9pt; font-family: Arial; color: rgb(51, 90, 143);" >DNI</td>
                    <td style="font-size: 9pt; font-family: Arial; color: rgb(51, 90, 143);" >${dni}</td>
                </tr>
                <tr>
                    <td style="font-size: 9pt; font-family: Arial; color: rgb(51, 90, 143);" >Direcci&oacute;n:</td>                
                    <td style="font-size: 9pt; font-family: Arial; color: rgb(51, 90, 143);" >${direccion},${cp} ${poblacion} - ${pais}</td>
                </tr>
                <tr>
                    <td style="font-size: 9pt; font-family: Arial; color: rgb(51, 90, 143);" >Telefono:</td>                
                    <td style="font-size: 9pt; font-family: Arial; color: rgb(51, 90, 143);" >${telefono}</td>
                </tr>
                <tr>
                    <td style="font-size: 9pt; font-family: Arial; color: rgb(51, 90, 143);" >Movil:</td>                
                    <td style="font-size: 9pt; font-family: Arial; color: rgb(51, 90, 143);" >${movil}</td>
                </tr>        
                <tr>
                    <td style="font-size: 9pt; font-family: Arial; color: rgb(51, 90, 143);" >Email:</td>                
                    <td style="font-size: 9pt; font-family: Arial; color: rgb(51, 90, 143);" >${mail}</td>
                </tr>    
                #if (${cliente} == $bar)        
                    <tr>
                        <td style="font-size: 9pt; font-family: Arial; color: rgb(51, 90, 143);" >N&uacute;mero cuenta:</td>                
                        <td style="font-size: 9pt; font-family: Arial; color: rgb(51, 90, 143);" >${numeroCuenta}</td>
                    </tr>    
                #end
            </table>
        </font>        
    </div>
    <br>
    <hr size="2" width="100%" align="left">
    <span style="font-size: 7.5pt; font-family: Arial; color: rgb(51, 90, 143);">
        .....
    </span>

- EmailServiceImpl.java
...
    private VelocityEngine velocityEngine;    
    private JavaMailSender javaMailSender;
    private String velocityTpl;
    
    private Map<String,Resource> inlineFiles;
    
    /**
     * Creaci�n y env�o de e-mail.
     * @param from E-mail de origen
     * @param recipients E-mails de destino
     * @param subject Asunto del e-mail
     * @param params Par�metros para la generaci�n del cuerpo del e-mail
     */
    public void sendEmail(String from, String[] recipients, String subject, Map<String,Object> params) {
        log.debug("sendEmail inicio");
        
        final String f = from;        
        final String s = subject;
        final Map<String,Object> p = params;
        
        for(final String to : recipients){
            MimeMessagePreparator preparator = new MimeMessagePreparator(){
                public void prepare(MimeMessage mimeMessage) throws Exception{
                    MimeMessageHelper helper = new MimeMessageHelper(mimeMessage,true);
                    helper.setFrom(f);
                    helper.setTo(to);
                    helper.setSubject(MimeUtility.encodeText(s, "iso-8859-1", "B"));                        
                    Map<String,Object> model = p;
                    String text = VelocityEngineUtils.mergeTemplateIntoString(velocityEngine,velocityTpl,model);
                    helper.setText(text, true);
                    
                    // añadiendo los ficheros "en línea"
                    if (getInlineFiles() != null) {
                        for (String key :getInlineFiles().keySet()) {
                            Resource value = getInlineFiles().get(key);
                            helper.addInline(key, value);
                            if (log.isDebugEnabled()) {
                                log.debug("File '" + value + "' added.");
                            }
                        }
                    }
                }
            };
            javaMailSender.send(preparator);
        }
        
        log.debug("sendEmail fin");
    }
    
    /**
     * Create and setup the mail sender component
     *  @param mailTO

     */
    public void initializeJavaMailSender(MailTO mailTO){        
        log.debug("initializeJavaMailSender inicio");
        
        //Create and setup the mail sender component
        JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
        mailSender.setHost(mailTO.getHostMail());
        mailSender.setPort(Integer.valueOf(mailTO.getPort()));    
        mailSender.setUsername(mailTO.getUsername());    
        mailSender.setPassword(mailTO.getPassword());
        
        //We need this setting for force Javamail to pass the login
        boolean mailSmtpAuth = mailTO.getMailSmtpAuth().equals("true");
        boolean starttls = mailTO.getStarttls().equals("true");
        
        Properties props = new Properties();
        if(mailSmtpAuth){
            log.debug("mailSmtpAuth true:"+mailTO.getMailSmtpAuth());
            props.setProperty("mail.smtp.auth", mailTO.getMailSmtpAuth());
        }
        if(starttls){
            log.debug("starttls true:" + mailTO.getStarttls());
            props.setProperty("mail.smtp.starttls.enable", mailTO.getStarttls());
        }
        mailSender.setJavaMailProperties(props);
        
        javaMailSender = mailSender;            
        
        log.debug("initializeJavaMailSender fin");
    }
...

- RegistrarseAction.java
// Enviar los datos por mail
        emailRegistrarseService.initializeJavaMailSender(mailTO);
        
        String[] recipients = mailTO.getToMail().split(";");
        String[] emailUsuario = mail.split(";");

        Map<String, Object> params = new HashMap<String, Object>();
        params.put("cliente", cliente);
        params.put("nombre", nombre);
        params.put("apellidos", apellidos);
        params.put("dni", dni);
        params.put("direccion", direccion);
        params.put("poblacion", poblacion);
        params.put("mail", mail);
        params.put("telefono", telefono);
        params.put("pais", pais);
        params.put("cp", cp);
        params.put("movil", movil);
        params.put("numeroCuenta", numeroCuenta);

        emailRegistrarseService.sendEmail(mail, recipients, 
                mailTO.getSubject(), params);