1
votes

I have a custom MailDto object in which I set the to,cc, bCc field and send it using RestTemplate to Spring MVC controller as below

@RequestMapping(value = "/SendMail"  )
    public ResponseEntity<String> SendMail( @RequestBody MailMessageDto mailDto)
            throws NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException

From the controller I invoke the Gateway (Spring integration). The Gateway has a method public void sendMail(MailMessageDto mailDto). The gateway channel invokes a transformer which converts the mailDto to MimeMessageHelper object. The mimeMessageHelper object is sent as a mail using a mailoutbound adapter. Now I want to send a mail using RestTemplate but with a attachment using same MailDto.

Problem is when I am changing the the Gateway and Transformmer method signature to accomodate the Multipart file and MailMessageDto which I will convert to MimeMessageHelper object in transform method spring integration is not able to understand the transform method.

I am wondering the what should be the signature of the controller method and how to declare the Transformer transform method in xml.

The mail-context file
<context:component-scan base-package="com.infra.mail,com.infra.audit " />  
    <mvc:annotation-driven />  

    <!-- <context:property-placeholder 
location="classpath:/mail.properties" ignore-unresolvable="true" /> -->

    <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}"/>
        <property name="defaultEncoding" value="UTF-8"/> 
        <property name="javaMailProperties">
            <props>
                <!-- Use SMTP transport protocol -->
                <prop key="mail.transport.protocol">smtp</prop>
                <!-- Use SMTP-AUTH to authenticate to SMTP server -->
                <prop key="mail.smtp.auth">true</prop>
                <!-- Use TLS to encrypt communication with SMTP server -->
                <prop key="mail.smtp.starttls.enable">false</prop>
                <prop key="mail.debug">true</prop>
            </props>
        </property>
    </bean>




     <int:channel id="xfromMailChannel">
    <int:queue/> 
    </int:channel>

The Transformer file

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;

import org.apache.log4j.Logger;
import org.apache.velocity.app.VelocityEngine;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.MailException;
import org.springframework.mail.MailMessage;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.ui.velocity.VelocityEngineUtils;


/**
 * The Class MailMessageTransformer.
 */
public class MailMessageTransformer {

/** The velocity engine. */
@Autowired
private VelocityEngine velocityEngine;

/** The mail sender. */
@Autowired
private JavaMailSender mailSender;

/** The Constant LOG. */
private static final Logger LOG = Logger.getLogger(MailMessageTransformer.class);



/**
* Transform MailMessageDto to SimpleMailMessage.
*
* @param mailDto the mail dto
* @return the mail message
*/
public MailMessage transformSimple(MailMessageDto mailDto) {

LOG.debug("MailMessageTransformer.transform.MailMessageDto:::" + mailDto);
if (mailDto == null) {
return null;
}

if (mailDto.getEncoding() == null) {
mailDto.setEncoding(IMailConstants.DEFAULT_ENCODING);
}

if (mailDto.getTemplateName() == null
|| !mailDto.getTemplateName().endsWith(IMailConstants.VELOCITY_TEMPLATE_EXTN)) {
mailDto.setTemplateName(getTemplateName(mailDto.getEmailType()));
}

SimpleMailMessage message = new SimpleMailMessage();

message.setFrom(mailDto.getFrom());
message.setTo(mailDto.getTo());
message.setSubject(mailDto.getSubject());
message.setText(getMailContent(mailDto));
message.setSentDate(new Date(System.currentTimeMillis()));

message.setBcc(mailDto.getBcc());
message.setCc(mailDto.getCc());
message.setReplyTo(mailDto.getReplyTo());

/*
* if (null != mailDto.getBcc()) { message.setBcc(mailDto.getBcc()); }
* if (null != mailDto.getBcc()) { message.setCc(mailDto.getCc()); } if
* (null != mailDto.getReplyTo() && !mailDto.getReplyTo().isEmpty()) {
* message.setReplyTo(mailDto.getReplyTo()); }
*/

LOG.debug("MailMessageTransformer.transform.message:::" + message);
return message;
}

/**
* Create the email content/body using velocity engine, velocity template
* and MailMessageDto.
*
* @param mailDto the mail dto
* @return the mail content
*/
private String getMailContent(MailMessageDto mailDto) {
Map<String, Object> model = getVelocityModel(mailDto);
String mailContent = VelocityEngineUtils.mergeTemplateIntoString(velocityEngine, mailDto.getTemplateName(),
mailDto.getEncoding(), model);
LOG.debug("MailMessageTransformer.getMailContent.mailContent:::" + mailContent);
return mailContent;
}

/**
* Create the Model Map referred in velocity mail template file.
*
* @param mailDto the mail dto
* @return the velocity model
*/
private Map<String, Object> getVelocityModel(MailMessageDto mailDto) {
Map<String, Object> model = new HashMap<String, Object>();
model.put(IMailConstants.VM_USER, getUser(mailDto.getTo()));
model.put(IMailConstants.VM_ALERT_TYPE, getAlertType(mailDto.getEmailType()));
model.put(IMailConstants.VM_CONTENT, mailDto.getText());
return model;
}

/**
* Fetch the user (receients) name from MailMessageDto. This is referred in
* velocity template file. Currently from TO email list. Can be changed to
* look up user store if future
*
* @param toList the to list
* @return the user
*/
private String getUser(String[] toList) {

StringBuffer user = new StringBuffer();

for (String mailId : toList.clone()) {
StringTokenizer token = new StringTokenizer(mailId, IMailConstants.EMAIL_AT);
String to = token.nextToken();
user.append(to).append(IMailConstants.COMMA);
}

return user.toString();
}

/**
* Fetch the email type from MailMessageDto. This is referred in velocity
* template file.
*
* @param emailType the email type
* @return the alert type
*/
private String getAlertType(String emailType) {

String alertType = IMailConstants.SYSTEM_ALERT_TEXT;

if (IMailConstants.REALTIME_EMAILTYPE.equalsIgnoreCase(emailType)) {
alertType = IMailConstants.REALTIME_ALERT_TEXT;
} else if (IMailConstants.OFFLINE_EMAILTYPE.equalsIgnoreCase(emailType)) {
alertType = IMailConstants.OFFLINE_ALERT_TEXT;
}

return alertType;
}

/**
* Fetch the name of velocity template file based on the emailType. Used by
* Velocity Engine.
*
* @param emailType the email type
* @return the template name
*/
private String getTemplateName(String emailType) {

String templateName = IMailConstants.SYSTEM_ALERT_VM;
if (IMailConstants.REALTIME_EMAILTYPE.equalsIgnoreCase(emailType)) {
templateName = IMailConstants.REALTIME_ALERT_VM;
} else if (IMailConstants.OFFLINE_EMAILTYPE.equalsIgnoreCase(emailType)) {
templateName = IMailConstants.OFFLINE_ALERT_VM;
}
return templateName;
}


/**
* Transform MailMessageDto to MimeMessage.
*
* @param mailDto the mail dto
* @return the mime message
*/
//public MimeMessage transform(final MailMessageDto mailDto,final CommonsMultipartFile file) {

public MimeMessage transform(MailMessageDto mailDto, final MultipartFile file) {



LOG.debug("MailMessageTransformer.transform.mailDto:::" + mailDto);

if (mailDto == null) {
return null;
}

if (mailDto.getEncoding() == null) {
mailDto.setEncoding(IMailConstants.DEFAULT_ENCODING);
}

if (mailDto.getTemplateName() == null
|| !mailDto.getTemplateName().endsWith(IMailConstants.VELOCITY_TEMPLATE_EXTN)) {
mailDto.setTemplateName(getTemplateName(mailDto.getEmailType()));
}

mailDto.setText(mailDto.getText().replaceAll(System.lineSeparator(), IMailConstants.HTML_NEW_LINE));

MimeMessage mimeMessage = null;
try {
String attachName = file.getOriginalFilename();
mimeMessage = mailSender.createMimeMessage();
MimeMessageHelper message = new MimeMessageHelper(mimeMessage);
message.setTo(mailDto.getTo());
message.setFrom(mailDto.getFrom());
message.setSubject(mailDto.getSubject());
message.setText(getMailContent(mailDto), IMailConstants.TRUE);
message.setSentDate(new Date(System.currentTimeMillis()));
message.addAttachment(attachName, new InputStreamSource() {

               @Override
               public InputStream getInputStream() throws IOException {
                   return file.getInputStream();
               }
           });


if (null != mailDto.getBcc()) {
message.setBcc(mailDto.getBcc());
}
if (null != mailDto.getBcc()) {
message.setCc(mailDto.getCc());
}
if (null != mailDto.getReplyTo() && !mailDto.getReplyTo().isEmpty()) {
message.setReplyTo(mailDto.getReplyTo());
}

}
catch (MessagingException msgex) {
LOG.error("MailMessageTransformer.transformMime.Exception::: MessagingException", msgex);

}
catch (MailException mailex) {
LOG.error("MailMessageTransformer.transformMime.Exception::: MailException ", mailex);

}

catch (Exception ex) {
LOG.error("MailMessageTransformer.transformMime.Exception::: Exception", ex);

}

LOG.debug("MailMessageTransformer.transformMime.mimeMessage:::" + mimeMessage);
return mimeMessage;
}

}

   <int:channel id="outboundMailChannel"/>
   <int:channel id="confirmationChannel"/>



   <int:gateway id="mailGateway" service-interface="com.infra.mail.MailGateway"
      default-request-channel="xfromMailChannel" default-reply-channel="confirmationChannel" error-channel="errorChannel">
      <int:method name="sendMail" payload-expression="#args[0] + #args[1]"> </int:method>
      </int:gateway>  


   <int:transformer input-channel="xfromMailChannel" output-channel="outboundMailChannel"
      ref="mailTransformer" method="transform">
        <int:poller fixed-rate="60000" max-messages-per-poll="100"/> 
  </int:transformer>

   <!-- Configure Mail Sender -->
   <int-mail:outbound-channel-adapter channel="outboundMailChannel" mail-sender="mailSender"/>

   <bean id="mailMessage" scope="prototype">
      <property name="from" value="${mail.user2}"/>
      <property name="replyTo" value="${mail.user3}"/>
   </bean>

   <bean id="mailTransformer" class="com.infra.mail.MailMessageTransformer"/>

</bean>

  <int:service-activator id="mailErrorChannelActivator" input-channel="errorChannel" ref="errorHandler" method="handleMailError"/>  
  <bean id="errorHandler" class="com.infra.audit.ErrorHandler"/>

  <int:channel-interceptor ref="infraInterceptor" pattern="*" order="3"/>
  <bean id="infraInterceptor" class="com.infra.audit.infraInterceptor"/>


    <int:channel id="sftpErrorChannel" />

  <int:chain input-channel="xfromMailChannel" output-channel="outboundMailChannel">
<int:header-enricher>
<int:error-channel ref="errorChannel" />
</int:header-enricher>
<int:poller fixed-rate="6000" max-messages-per-poll="1"/> 
</int:chain>

**The Gateway file**
public interface MailGateway {

/**
* Send mail.
*
* @param mailDto the mail dto
*/

@Gateway
public void sendMail(MailMessageDto mailDto, MultipartFile file);

}
3
Please, share Spring Integration config and your Java code on the matter. We can't help just believing to your words. Moreover I don't see anything specific: if you need attachment, you have to create MimeMessageHelper in your transformer and so on. Maybe your issue in the gateway's method, when Spring Integration doesn't like ambiguity with params, where only one can be payload of the future message. - Artem Bilan
The question is updated with info - LONGHORN007

3 Answers

2
votes

you have add mailapi.jar in lib folder then xml file in creating bean for mailsend

<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
        <property name="host" value="smtp.gmail.com" />
        <property name="port" value="587" />
        <property name="username" value="yourmailid" />
        <property name="password" value="password" />
        <property name="javaMailProperties">
            <props>
                <prop key="mail.transport.protocol">smtp</prop>
                <prop key="mail.smtp.auth">true</prop>
                <prop key="mail.smtp.starttls.enable">true</prop>
            </props>
        </property>
    </bean>  

controller code

@RequestMapping(value="/sendMail.do",method=RequestMethod.POST)
    public ModelAndView sendMail(@RequestParam("email")String email){
        ModelAndView model = new ModelAndView("redirect:login.do");
        List<User_master> userList = adminService.getAllUser();
        for(User_master user: userList)
        {
            String e = user.getUser_Email();
            if(e.equals(email))
            {
                String Subject="Forget Username and Password";
                String username = user.getUser_Name();
                String password = user.getUser_Password();
                String message = "User Name : "+ username + " and " +"Password : "+ password;
                SimpleMailMessage obj_email = new SimpleMailMessage();
                obj_email.setTo(email);
                obj_email.setSubject(Subject);
                obj_email.setText(message);
                mailSender.send(obj_email);
                return model;
            }
            else
            {

            }
        }
        return model;
    }
1
votes

First:

@Gateway
public void sendMail(MailMessageDto mailDto, MultipartFile file);

Second:

public MimeMessage transform(MailMessageDto mailDto, final MultipartFile file) {

Please, read Spring Integration Manual closely.

So, you should understand here that Spring Integration (and any Messaging) gets deal exactly with Message. It is a honor to Framework that it allows us to use POJO method-invocation style interaction, but we should follow here with simple rules.

Only one method argument for payload. Yes, in some places like @Publisher we can use SpEL for @Payload value to build payload from several arguments, but in general only one of them can be as a payload: or that one which is marked with @Payload, or that one which isn't Map<String, Object> to be treated as MessageHeaders.

You may not mark it with @Payload but then you must to do similar for all others - mark them with @Header.

So, to fix your issue you should do this:

@Gateway
public void sendMail(MailMessageDto mailDto, @Header("file") MultipartFile file);

and:

public MimeMessage transform(MailMessageDto mailDto, @Header("file") final MultipartFile file) {
0
votes
    DateFormat df = new SimpleDateFormat("dd/MM/yy HH:mm:ss");
    Calendar calobj = Calendar.getInstance();
    String date1 = df.format(calobj.getTime());
    System.out.println(df.format(calobj.getTime()));

    try {

        // Email data
        String Email_Id = "ypur email";
        String password = "your pswrd";
        String recipient_mail_id = "client email";
        String mail_subject = "Attendance Report";

        System.out.println(sentEmailFrom);
        System.out.println(emailPassword);
        System.out.println(sentEmailTo);

        // Set mail properties
        Properties props = System.getProperties();
        String host_name = "smtp.gmail.com";
        props.put("mail.smtp.starttls.enable", "true");
        props.put("mail.smtp.host", host_name);
        props.put("mail.smtp.user", Email_Id);
        props.put("mail.smtp.password", password);
        props.put("mail.smtp.port", "587");
        props.put("mail.smtp.auth", "true");

        Session session = Session.getDefaultInstance(props);
        MimeMessage message = new MimeMessage(session);

        try {
            // Set email data
            message.setFrom(new InternetAddress(Email_Id));
            message.addRecipient(Message.RecipientType.TO, new InternetAddress(recipient_mail_id));
            message.setSubject(mail_subject);
            MimeMultipart multipart = new MimeMultipart();
            BodyPart messageBodyPart = new MimeBodyPart();
            // Set key values
            Map<String, String> input = new HashMap<String, String>();
            input.put("User", presentUser.toString());
            input.put("Date", date1);
            input.put("Content In", "English");
            input.put("Absent", absentUser);
            input.put("Late", lateUser);
            // HTML mail content
            ClassLoader loader = SendMailService.class.getClassLoader();
            URL url = loader.getResource("mailTemplate.html");
            String path = url.toString().replace("file:", "");
            System.out.println(path);
            String htmlText = readEmailFromHtml(path, input);
            messageBodyPart.setContent(htmlText, "text/html");
            multipart.addBodyPart(messageBodyPart);
            message.setContent(multipart);
            // Conect to smtp server and send Email
            Transport transport = session.getTransport("smtp");
            transport.connect(host_name, Email_Id, password);
            transport.sendMessage(message, message.getAllRecipients());
            transport.close();
            log.info("Mail Sent Successfully..!");
        } catch (MessagingException ex) {
        } catch (Exception ae) {
            ae.printStackTrace();
        }
    } catch (Exception exception) {
        exception.printStackTrace();
    }
}

// Method to replace the values for keys
protected String readEmailFromHtml(String filePath, Map<String, String> input) {
    String msg = readContentFromFile(filePath);
    try {
        Set<Entry<String, String>> entries = input.entrySet();
        for (Map.Entry<String, String> entry : entries) {
            msg = msg.replace(entry.getKey().trim(), entry.getValue().trim());
        }
    } catch (Exception exception) {
        exception.printStackTrace();
    }
    return msg;
}

// Method to read HTML file as a String
private String readContentFromFile(String fileName) {
    StringBuffer contents = new StringBuffer();

    try {
        // use buffering, reading one line at a time
        BufferedReader reader = new BufferedReader(new FileReader(fileName));
        try {
            String line = null;
            while ((line = reader.readLine()) != null) {
                contents.append(line);
                contents.append(System.getProperty("line.separator"));
            }
        } finally {
            reader.close();
        }
    } catch (IOException ex) {
        ex.printStackTrace();
    }
    return contents.toString();
}

}