Spring + Thymeleaf mail template - why are inline images attached to email? - spring

I'm using spring + thymeleaf to send emails. My mail template has few images which are displayed properly in the email, however i see that unused images are attached to the bottom of the email. I have business logic in the html, which decides what images to show and what not, so sometimes some images are not used but are attached. How do i get rid of them?
Any ideas?
Here is how i load the image in html:
<img src="cid:change-password" alt="">
Here is how i send the email:
public void sendUsingTemplate(String fromEmail, String toEmail, String subject, String templateName, Map<String, Object> variables) {
MimeMessage message = mailSender.createMimeMessage();
try {
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setSubject(subject);
final Context context = new Context(Locale.getDefault());
variables.forEach((name, value) -> context.setVariable(name, value));
String text = templateEngine.process(templateName, context);
helper.setText(text, true);
helper.setFrom(fromEmail);
helper.setTo(toEmail);
Map<String, String> inlineResources = mailTemplateResourcesProvider.getInlineResources(templateName);
inlineResources.forEach((contentId, file) -> addInlineWithoutCheckedException(helper, contentId, file));
mailSender.send(message);
} catch (Exception e) {
logger.error("Error sending mail using template", e);
}

Related

Send image in thymeleaf

I want to send a message via email in which the alert and image will be sent using thymeleaf, but I do not want to send it in the implementation method of sending the message, since I cannot make changes to this image in any way, can I add an image to the html code? I try to add an image to the html code, the image does not open and I can't do anything with it, I want the image to appear and I could transfer text to it
public void send(String emailTo, String subject, String message,String content) throws MessagingException, IOException {
MimeMessage mimeMessage = mailSender.createMimeMessage();
mimeMessage.setSubject(subject);
mimeMessage.setContent(content, "HTML5");
MimeMessageHelper helper;
helper = new MimeMessageHelper(mimeMessage, true);
helper.setFrom(username);
helper.setTo(emailTo);
helper.setText(message,true);
// FileSystemResource file = new FileSystemResource(new File("src/main/resources/templates/image/valayev.jpg"));
// helper.addInline("valyaev", file);
mailSender.send(mimeMessage);

send mail through spring boot application

I am creating spring boot application where I have to send newly generated response string for each transaction to user as a text file attachment
so what will be the proper way to do this
any help would be appreciated
Try this below code:
#Override
public void sendMessageWithAttachment(
String to, String subject, String text, String pathToAttachment) {
// ...
MimeMessage message = emailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setTo(to);
helper.setSubject(subject);
helper.setText(text);
FileSystemResource file
= new FileSystemResource(new File(pathToAttachment));
helper.addAttachment("Invoice", file);
emailSender.send(message);
// ...
}

Couldn't prepare mail with inline image using Thymeleaf templateEngine?

I am trying to send a html email with an inline-image attached using spring mvc and Thymeleaf. My code works without attaching the image. I get the html email successfully without image. But When I added the following line to my code I get the below error message.
Without this line code works and I get the email without image:
message.addInline(image.getName(), imageSource, image.getContentType());
This is the method:
public void sendUserRegisterEmail(String receiver, String receiverEmailAddress){
MimeMessagePreparator preparator = new MimeMessagePreparator() {
public void prepare(MimeMessage mimeMessage) throws Exception {
Path path = Paths.get("/assets/dist/img/dialog_tv_logo-white-01.png");
String fileName = "dialog_tv_logo-white-01.png";
String originalFileName = "dialog_tv_logo-white-01.png";
String contentType = "image/png";
byte[] content = null;
try {
content = Files.readAllBytes(path);
} catch (final IOException e) {
}
MultipartFile image = new MockMultipartFile(fileName,
originalFileName, contentType, content);
Locale locale = Locale.getDefault();
final Context ctx = new Context(locale);
ctx.setVariable("name", receiver);
ctx.setVariable("subscriptionDate", new Date());
ctx.setVariable("imageResourceName", image.getName());
MimeMessageHelper message = new MimeMessageHelper(mimeMessage);
message.setSubject(USER_REGISTER_MESSAGE_SUBJECT);
message.setTo(receiverEmailAddress);
message.setFrom(SENDER_EMAIL_ADDRESS);
final String htmlContent = emailTemplateEngine.process("email-inlineimage", ctx);
message.setText(htmlContent, true /* isHtml */);
final InputStreamSource imageSource = new ByteArrayResource(image.getBytes());
message.addInline(image.getName(), imageSource, image.getContentType());
}
};
sendEmail(preparator);
}
Following error message I get when the image prepare line is added:
org.springframework.mail.MailPreparationException: Could not prepare mail; nested exception is java.lang.IllegalStateException: Not in multipart mode - create an appropriate MimeMessageHelper via a constructor that takes a 'multipart' flag if you need to set alternative texts or add inline elements or attachments.
Can any one figure out what is the issue here?
Finally able to fix the error after a lot of effort. Changing the following line fixed the issue. Create MimeMessageHelper by passing true
MimeMessageHelper message = new MimeMessageHelper(mimeMessage, true);

SpringBoot: Large Streaming File Upload Using Apache Commons FileUpload

Am trying to upload a large file using the 'streaming' Apache Commons File Upload API.
The reason I am using the Apache Commons File Uploader and not the default Spring Multipart uploader is that it fails when we upload very large file sizes (~2GB). I working on a GIS application where such file uploads are pretty common.
The full code for my file upload controller is as follows:
#Controller
public class FileUploadController {
#RequestMapping(value="/upload", method=RequestMethod.POST)
public void upload(HttpServletRequest request) {
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
if (!isMultipart) {
// Inform user about invalid request
return;
}
//String filename = request.getParameter("name");
// Create a new file upload handler
ServletFileUpload upload = new ServletFileUpload();
// Parse the request
try {
FileItemIterator iter = upload.getItemIterator(request);
while (iter.hasNext()) {
FileItemStream item = iter.next();
String name = item.getFieldName();
InputStream stream = item.openStream();
if (item.isFormField()) {
System.out.println("Form field " + name + " with value " + Streams.asString(stream) + " detected.");
} else {
System.out.println("File field " + name + " with file name " + item.getName() + " detected.");
// Process the input stream
OutputStream out = new FileOutputStream("incoming.gz");
IOUtils.copy(stream, out);
stream.close();
out.close();
}
}
}catch (FileUploadException e){
e.printStackTrace();
}catch (IOException e){
e.printStackTrace();
}
}
#RequestMapping(value = "/uploader", method = RequestMethod.GET)
public ModelAndView uploaderPage() {
ModelAndView model = new ModelAndView();
model.setViewName("uploader");
return model;
}
}
The trouble is that the getItemIterator(request) always returns an iterator that does not have any items (i.e. iter.hasNext() ) always returns false.
My application.properties file is as follows:
spring.datasource.driverClassName=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://localhost:19095/authdb
spring.datasource.username=georbis
spring.datasource.password=asdf123
logging.level.org.springframework.web=DEBUG
spring.jpa.hibernate.ddl-auto=update
multipart.maxFileSize: 128000MB
multipart.maxRequestSize: 128000MB
server.port=19091
The JSP view for the /uploader is as follows:
<html>
<body>
<form method="POST" enctype="multipart/form-data" action="/upload">
File to upload: <input type="file" name="file"><br />
Name: <input type="text" name="name"><br /> <br />
Press here to upload the file!<input type="submit" value="Upload">
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
</form>
</body>
</html>
What might I be doing wrong?
Thanks to some very helpful comments by M.Deinum, I managed to solve the problem. I have cleaned up some of my original post and am posting this as a complete answer for future reference.
The first mistake I was making was not disabling the default MultipartResolver that Spring provides. This ended up in the resolver processing the HttpServeletRequest and thus consuming it before my controller could act on it.
The way to disable it, thanks to M. Deinum was as follows:
multipart.enabled=false
However, there was still another hidden pitfall waiting for me after this. As soon as I disabled default multipart resolver, I started getting the following error when trying to make an upload:
Fri Sep 25 20:23:47 IST 2015
There was an unexpected error (type=Method Not Allowed, status=405).
Request method 'POST' not supported
In my security configuration, I had enabled CSRF protection. That necessitated that I send my POST request in the following manner:
<html>
<body>
<form method="POST" enctype="multipart/form-data" action="/upload?${_csrf.parameterName}=${_csrf.token}">
<input type="file" name="file"><br>
<input type="submit" value="Upload">
</form>
</body>
</html>
I also modified my controller a bit:
#Controller
public class FileUploadController {
#RequestMapping(value="/upload", method=RequestMethod.POST)
public #ResponseBody Response<String> upload(HttpServletRequest request) {
try {
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
if (!isMultipart) {
// Inform user about invalid request
Response<String> responseObject = new Response<String>(false, "Not a multipart request.", "");
return responseObject;
}
// Create a new file upload handler
ServletFileUpload upload = new ServletFileUpload();
// Parse the request
FileItemIterator iter = upload.getItemIterator(request);
while (iter.hasNext()) {
FileItemStream item = iter.next();
String name = item.getFieldName();
InputStream stream = item.openStream();
if (!item.isFormField()) {
String filename = item.getName();
// Process the input stream
OutputStream out = new FileOutputStream(filename);
IOUtils.copy(stream, out);
stream.close();
out.close();
}
}
} catch (FileUploadException e) {
return new Response<String>(false, "File upload error", e.toString());
} catch (IOException e) {
return new Response<String>(false, "Internal server IO error", e.toString());
}
return new Response<String>(true, "Success", "");
}
#RequestMapping(value = "/uploader", method = RequestMethod.GET)
public ModelAndView uploaderPage() {
ModelAndView model = new ModelAndView();
model.setViewName("uploader");
return model;
}
}
where Response is just a simple generic response type I use:
public class Response<T> {
/** Boolean indicating if request succeeded **/
private boolean status;
/** Message indicating error if any **/
private String message;
/** Additional data that is part of this response **/
private T data;
public Response(boolean status, String message, T data) {
this.status = status;
this.message = message;
this.data = data;
}
// Setters and getters
...
}
If you're using a recent version of spring boot (I'm using 2.0.0.M7) then the property names have changed.
Spring started using technology specific names
spring.servlet.multipart.maxFileSize=-1
spring.servlet.multipart.maxRequestSize=-1
spring.servlet.multipart.enabled=false
If you're getting StreamClosed exceptions caused by multiple implementations being active, then the last option allows you to disable the default spring implementation
Please try to add spring.http.multipart.enabled=false in application.properties file.
I use kindeditor + springboot. When I use (MultipartHttpServletRequest) request. I could get the file, but I use appeche-common-io:upload.parse(request) the return value is null.
public BaseResult uploadImg(HttpServletRequest request,String type){
MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
MultiValueMap<String, MultipartFile> multiFileMap = multipartRequest.getMultiFileMap();
You Can simply add spring properties:
spring.servlet.multipart.max-file-size=20000KB
spring.servlet.multipart.max-request-size=20000KB
here my maximum file size is 20000KB, you can change if required.

How to get HttpServletRequest object in Spring Schedular (#Schedule)?

I am trying to send a mail using spring scheduler. In that I need HttpServletRequest object to create webContext, so that I can send mail using thyme leaf.
Anyone know the answer of this. Thanks in advance. Code is as follows,
#Async
private void sendNotification(String toField, Users user, int currentMonth)
throws Exception {
// Prepare the evaluation context
#SuppressWarnings("deprecation")
**//here i need request object**
final WebContext ctx = new WebContext(request, request.getSession()
.getServletContext(), request.getLocale());
ctx.setVariable("eagletId", user.getEagletId());
ctx.setVariable("name", user.getFirstName());
ctx.setVariable("setSentDate", new Date());
ctx.setVariable("department", user.getDepartment());
ctx.setVariable("batch", user.getBatch());
MimeMessage message = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8");
helper.setTo(user.getEmail());
// create html body using thymeleaf
final String htmlContent = this.templateEngine.process("email.html",
ctx);
helper.setText(htmlContent, true);
mailSender.send(message);
}

Resources