Sending Email with Attachments in Spring Boot - java

I'm trying to send an email with file attachments in Spring Boot.
This is a basic gmail SMTP server application properties config:
This is my EmailService:
EmailService
When I call this method with mailMessageDto object passed, there is no exception thrown. Nothing happens, e-mail isn't sent.
I have debugged on javaMailSender.send(messsage) line of code and everything seems fine.
Update
spring.mail.properties.mail.smtp.ssl.enable=false
should be false not true spring.mail.properties.mail.smtp.socketFactory.class=javax.net.ssl.SSLSocketFactory

step 1. add dependencies in porm.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
step 2. add configuration code in application.properties
spring.mail.host=smtp.gmail.com
spring.mail.port=465
spring.mail.username=username
spring.mail.password=password
spring.mail.protocol=smtps
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.connectiontimeout=5000
spring.mail.properties.mail.smtp.timeout=5000
spring.mail.properties.mail.smtp.writetimeout=5000
spring.mail.properties.mail.smtp.starttls.enable=true
step 3. add code in controller
masterconroller.java
#GetMapping("/sendmail")
#ResponseBody
String home() {
try {
masterServiceImpl.sendEmail("path");
return "Email Sent!";
} catch (Exception ex) {
return "Error in sending email: " + ex;
}
}
step 4. add code in MasterServiceImpl.java
#Autowired
private JavaMailSender javaMailSender;
public void sendEmail(String path) throws Exception{
MimeMessage message = javaMailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setTo("xyz#gmail.com");
helper.setText("<html><body><h1>hello Welcome!</h1><body></html>", true);
FileSystemResource file = new FileSystemResource(new File(path));
helper.addAttachment("testfile", file);
helper.addAttachment("test.png", new ClassPathResource("test.jpeg"));
helper.setSubject("Hi");
javaMailSender.send(message);
}

I propose you to apply SRP to sendMessageWithAttachment() method by extracting functionality around adding attachments:
private void addAttachments(MailMessageDto message, MimeMessageHelper helper) {
message.getFiles().forEach(file -> addAttachment(file, helper));
}
This method streams over all files and adds every file by using addAttachment():
private void addAttachment(File file, MimeMessageHelper helper) {
String fileName = file.getName();
try {
helper.addAttachment(fileName, file);
log.debug("Added a file atachment: {}", fileName);
} catch (MessagingException ex) {
log.error("Failed to add a file atachment: {}", fileName, ex);
}
}
This will log an error for each failed attachment. Can you try this approach?

Related

How can I automatically get file in java from s3?

#Value("${amazon.sqs.queue.endpoint}")
private String endpoint;
#Value("${amazon.sqs.queue.name}")
private String queueName;
#Autowired
private SQSListener sqsListener;
#Bean
public DefaultMessageListenerContainer jmsListenerContainer() throws JMSException {
SQSConnectionFactory sqsConnectionFactory = SQSConnectionFactory.builder()
.withAWSCredentialsProvider(new DefaultAWSCredentialsProviderChain())
.withEndpoint(endpoint)
.withAWSCredentialsProvider(new ClasspathPropertiesFileCredentialsProvider("AwsCredentials-sqs.properties"))
.withNumberOfMessagesToPrefetch(10).build();
DefaultMessageListenerContainer dmlc = new DefaultMessageListenerContainer();
dmlc.setConnectionFactory(sqsConnectionFactory);
dmlc.setDestinationName(queueName);
dmlc.setConcurrentConsumers(1);
dmlc.setMaxConcurrentConsumers(100);
dmlc.setMessageListener(sqsListener);
return dmlc;
}
#Component
public class SQSListener implements MessageListener {
private static final Logger LOGGER = LoggerFactory.getLogger(SQSListener.class);
#Override
public void onMessage(Message message) {
try {
// Cast the recei
ved message as TextMessage and print the text to screen.
System.out.println("Received: " + ((TextMessage) message).getText());
} catch (JMSException e) {
e.printStackTrace();
}
}
}
I added a file in s3 then the message was sent to sqs queue.
after getting this message can I get the actual data, that was uploaded in s3?
It's not clear from your question what the message contains, but if the message contains the S3 bucket and key, then yes, you can just use the S3 API to download this.
Add the following dependency
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>s3</artifactId>
</dependency>
This logic will create the S3 client and download the object.
AwsCredentials credentials = AwsBasicCredentials.create(
"<AWS Access Key>",
"<AWS Secret>"
);
S3Client s3client = S3Client.builder()
.region(Region.US_EAST_1) // or whatever region you're in
.credentialsProvider(() -> credentials) // credentials created above (or preferably injected)
.build();
GetObjectRequest getObjectRequest = GetObjectRequest.builder()
.bucket("the bucket") // the bucket that contains the object, from message maybe?
.key("the key") // the key to the object, from message maybe?
.build();
ResponseInputStream<GetObjectResponse> responseInputStream = s3client.getObject(getObjectRequest);
This will give you an InputStream that you can read from.

FileNotFound when sending mail with attachment with Javamail

I'm trying to send a mail with an attachment file by using Javamail. But when the code is trying to read the content of the file a FileNoFound exception is raised.
The weird thing is that in debug mode I can see that it gets the file (the MultiPartFile variable isn't empy). I'm also using #Async so maybe it's the real issue.
My method sendMail :
#Async("threadPoolTaskExecutor")
public void sendMail(Context ctx, String dest, String subject, String templateName, MultipartFile attachment)
throws MessagingException, MailException, IOException {
MimeMessage mimeMessage = emailSender.createMimeMessage();
MimeMessageHelper message = new MimeMessageHelper(mimeMessage, true, "UTF-8");
message.setFrom("test#test.com");
message.setTo(dest);
message.setSubject(subject);
String htmlContent = emailTemplateEngine.process(templateName, ctx);
message.setText(htmlContent, true); // true = isHtml
if (attachment != null) {
InputStreamSource attachmentSource;
attachmentSource = new ByteArrayResource(attachment.getBytes());
message.addAttachment(attachment.getOriginalFilename(), attachmentSource);
}
emailSender.send(mimeMessage);
}
The error I'm having is :
java.io.FileNotFoundException: C:\Users\user\AppData\Local\Temp\tomcat.970471969296194243.8080\work\Tomcat\localhost\ROOT\upload_a28782c3_18d7_4b6b_84b7_2d9e81e9a692_00000007.tmp
at java.io.FileInputStream.open0(Native Method)
at java.io.FileInputStream.open(FileInputStream.java:195)
at java.io.FileInputStream.<init>(FileInputStream.java:138)
at org.apache.tomcat.util.http.fileupload.disk.DiskFileItem.getInputStream(DiskFileItem.java:194)
at org.apache.catalina.core.ApplicationPart.getInputStream(ApplicationPart.java:100)
at org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile.getBytes(StandardMultipartHttpServletRequest.java:245)
[...]
Edit: I tried removing the #Async and the file is uploaded without any errors. So this is the cause of my FileNotFound exception... So is there any way to solve this because I would very much like to put this method on async. I don't know much about async and thread managing so maybe I just can't use it when uploading files (?)
your code does not seem to explain what is emailTemplateEngine is.
usually your server does not copy custom templates by default. check dir C:\Users\user\AppData\Local\Temp\tomcat.970471969296194243.8080\work\Tomcat\localhost\ROOT\
it should be defined out of the box.
you can try using freemarker.template.Configuration
private Configuration initialiseFreeMarkerConfiguration() throws IOException, TemplateException {
FreeMarkerConfigurationFactoryBean factory = new FreeMarkerConfigurationFactoryBean();
factory.setTemplateLoaderPath("classpath:/ROOT/");
factory.setPreferFileSystemAccess(false);
return factory.createConfiguration();
}
your code...
private final Configuration freeMarkerConfiguration;
// in method
MimeMessage mimeMessage = emailSender.createMimeMessage();
MimeMessageHelper message = new MimeMessageHelper(mimeMessage, true, "UTF-8");
message.setFrom("test#test.com");
message.setTo(dest);
message.setSubject(subject);
message.setText(processEmailFromTemplate(model), true);
//attachment logic, use FileSystemResource instead of ByteArrayResource
if (attachment != null) {
InputStreamSource attachmentSource;
FileSystemResource file = new FileSystemResource(new File(attachment));
message.addAttachment(attachment.getOriginalFilename(), file );
}
emailSender.send(mimeMessage);
method processEmailFromTemplate() should do something like this.
private String processEmailFromTemplate(Map<String, Object> model) throws IOException, TemplateException {
StringBuilder content = new StringBuilder();
content.append(FreeMarkerTemplateUtils.processTemplateIntoString(freeMarkerConfiguration.getTemplate("your template name"), model));
return content.toString();
}

Upload Binary file on aws s3 using java Spring

I am able to upload file Using Form data as given below
but when i am trying to upload file by selecting binary as input getting error as given below;
{"timestamp":1490680735011,"status":500,"error":"Internal Server Error","exception":"org.springframework.web.multipart.MultipartException","message":"Current request is not a multipart request","path":"/uploadBinary"}
for that i am writing code as
#RequestMapping(value = "/uploadBinary", method = RequestMethod.POST)
public ResponseEntity<Object> uploadBinary(
#RequestParam("file") MultipartFile[] multipartFiles) {
try {
System.out.println("starting....");
fileService.upload(multipartFiles);
System.out.println("uploaded successfully ");
} catch (Exception ex) {
System.out.println(ex.getMessage());
return new ResponseEntity<Object>(new String(
"Something Went wrong while uploading data to server"),
HttpStatus.OK);
}
return new ResponseEntity<Object>(new String("uploaded successfully "),
HttpStatus.OK);
}
this works fine for uploading form data, but for binary selection its not working. how we resolve this issues??
Check whether you have added CommonsMultipartResolver in your spring configuration file
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"/>

Send file from Server to Client java with Spring and Rest web service

I have to send file from Server (from its file system) to Cliente (another pc and store file in a particularly folder) through java code and Rest web service. These files can be even 120MB.
I used MultipartFile to upload file from my web page but I don't know how to download from the client.
It would be good the possibility to use a REST web service that returns both file and message with result of method (true or false if there was an error).
Do you have an idea?
At the moment I use this code in server:
and the best way would be
#Override
#RequestMapping(value = "/oldmethod", method = RequestMethod.GET)
public #ResponseBody Response getAcquisition(#RequestParam(value="path", defaultValue="/home") String path){
File file;
try {
file = matlabClientServices.getFile(path);
if (file.exists()){
InputStream inputStream = new FileInputStream(path);
byte[]out=org.apache.commons.io.IOUtils.toByteArray(inputStream);
return new Response(true, true, out, null);
}
else
return new Response(false, false, "File doesn't exist!", null);
} catch (Exception e) {
ErrorResponse errorResponse= ErrorResponseBuilder.buildErrorResponse(e);
LOG.error("Threw exception in MatlabClientControllerImpl::getAcquisition :" + errorResponse.getStacktrace());
return new Response(false, false, "Error during file retrieving!", errorResponse);
}
}
but to the client the code below doesn't work:
public Response getFileTest(#RequestParam(value="path", defaultValue="/home") String path){
RestTemplate restTemplate = new RestTemplate();
Response response = restTemplate.getForObject("http://localhost:8086/ATS/client/file/oldmethod/?path={path}", Response.class, path);
if (response.isStatus() && response.isSuccess()){
try {
Files.write(Paths.get("PROVIAMOCI.txt"),org.apache.commons.io.IOUtils.toByteArray(response.getResult().toString()));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return response;
}
it writes the byte[] characters and not the original text
As per my understanding FileSystemResource used for get the file system using file system URI but it is not over the HTTP. Using FileSystemResource you can access files from your local machine to local accessible file system and from server to your server accesiable file system. But could not access from local to server file system.

Send bulk emails in Apache Camel without closing connection

Does Apache Camel Mail Component support reuse of TCP connection for sending bulk emails?
If not, is it feasible/recommendable to write custom org.apache.camel.component.mail.JavaMailSender to do so?
I think it's not possible with the standard camel mail component and also implementing a JavaMailSender won't do the trick for you imo.
If you have a look at org.apache.camel.component.mail.MailProducer(2.13.0):
public void process(final Exchange exchange) {
try {
MimeMessage mimeMessage;
final Object body = exchange.getIn().getBody();
if (body instanceof MimeMessage) {
// Body is directly a MimeMessage
mimeMessage = (MimeMessage) body;
} else {
// Create a message with exchange data
mimeMessage = new MimeMessage(sender.getSession());
getEndpoint().getBinding().populateMailMessage(getEndpoint(), mimeMessage, exchange);
}
if (LOG.isDebugEnabled()) {
LOG.debug("Sending MimeMessage: {}", MailUtils.dumpMessage(mimeMessage));
}
sender.send(mimeMessage);
// set the message ID for further processing
exchange.getIn().setHeader(MailConstants.MAIL_MESSAGE_ID, mimeMessage.getMessageID());
} catch (MessagingException e) {
exchange.setException(e);
} catch (IOException e) {
exchange.setException(e);
}
}
There is only 1 message or exchange object send/handled.
So maybe implementing your own "BulkMailComponent" with the functionality you need can be a solution for you.

Categories