Reputation: 6624
I'm trying to send an email with an inline image using ThymeLeaf and Spring, but so far no success. The email sends, but the inline image won't show in the email.
The project is not web-based (not a website), but is a desktop stand-alone, not mobile
This is how I get the image file:
URL url = getClass().getResource("/LawFirmAdvisoryGroup.jpg");
File file = new File(url.getPath());
MultipartFile multipartFile = new MockMultipartFile(file.getName(),
file.getName(), "image/jpeg", IOUtils.toByteArray(input));
My service class:
@Autowired
private JavaMailSender mailSender;
@Autowired
private TemplateEngine templateEngine;
public void sendMailWithInline(final String recipientName, final String recipientEmail, final MultipartFile image, final byte[] imageBytes)
throws MessagingException {
final Context ctx = new Context();
ctx.setVariable("imageResourceName", image.getName()); // so that we can reference it from HTML
final MimeMessage mimeMessage = this.mailSender.createMimeMessage();
final MimeMessageHelper message
= new MimeMessageHelper(mimeMessage, true, "UTF-8");
message.setSubject("Inline Image");
message.setFrom("[email protected]");
message.setTo(recipientEmail);
// Add the inline image, referenced from the HTML code as "cid:${imageResourceName}"
final InputStreamSource imageSource = new ByteArrayResource(imageBytes);
message.addInline(image.getName(), imageSource, image.getContentType());
final String htmlContent = this.templateEngine.process("left_sidebar.html", ctx);
message.setText(htmlContent, true);
this.mailSender.send(mimeMessage);
}
The HTML:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title th:remove="all">Email with inline image</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<p>
<img src="LawFirmAdvisoryGroup.jpg" th:src="'cid:' + ${imageResourceName}" />
</p>
</body>
</html>
Upvotes: 8
Views: 18512
Reputation: 1903
@Component
@RequiredArgsConstructor
@Slf4j
public class EmailSenderService {
private final JavaMailSender emailSender;
private final SpringTemplateEngine templateEngine;
public void sendEmail (MailDto mailDto, String nameTemplate) {
MimeMessage message = emailSender.createMimeMessage();
MimeMessageHelper helper;
try {
helper = new MimeMessageHelper(message,
MimeMessageHelper.MULTIPART_MODE_MIXED_RELATED,
StandardCharsets.UTF_8.name ());
ClassPathResource attachment = new ClassPathResource("static/pdf/practice-react-programming.pdf");
ClassPathResource image = new ClassPathResource("static/img/auth.png");
helper.addAttachment("reactive-programming-book", attachment);
helper.setTo(mailDto.mailTo());
helper.setSubject(mailDto.subject());
/*it is important to specify the same sender address that you have specified in application.yml*/
helper.setFrom(mailDto.mailFrom());
Context context = new Context();
context.setVariables(mailDto.propertiesMail());
String html = templateEngine.process(nameTemplate, context);
helper.setText(html, true);
/*This must be set after calling the method setText()*/
helper.addInline("auth", image);
} catch (MessagingException e) {
log.error(e.getLocalizedMessage());
// throw new RuntimeException(e);
}
emailSender.send(message);
}
}
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns:th="http://www.thymeleaf.org" xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Thymeleaf и Spring boot</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<link href='http://fonts.googleapis.com/css?family=Roboto' rel='stylesheet' type='text/css'/>
<!-- use the font -->
<style>
body {
font-family: 'Roboto', sans-serif;
font-size: 48px;
}
.circle {
border-radius: 50%;
border: 5px solid #fff;
box-shadow: 2px 1px 5px #999999;
}
p {
font-size: 25px;
font-family: Cambria;
}
</style>
</head>
<body>
<p th:text="${'Hello Dear ' + name}"></p>
<p th:if="${name.length() > 5}">
you name ...
</p>
<p>
<b>Authentication has being passed.</b>
<span th:text="${#dates.format(#dates.createNow(), 'dd MMM yyyy HH:mm')}"></span>
</p>
<p>
text...
</p>
<p>
<!--for external images.-->
<a href="https://kipmu.ru/wp-content/uploads/ksplshd-scaled.jpg">
<img src="https://kipmu.ru/wp-content/uploads/ksplshd-scaled.jpg"
alt="http://localhost.com"
height="220"
width="220"
class="circle"/>
</a>
</p>
<p>Attached images</p>
<p>
<img src="cid:auth" alt="http://localhost.com"
height="220"
width="220"
class="circle" />
</p>
<p>
Regardless, <br/>
<em th:text="${sign}"></em>
<p th:text="${location}"></p>
</p>
</body>
</html>
Upvotes: 0
Reputation: 496
Just move your call to setText()
up a few lines.
The javadoc for MimeMessageHelper.addInLine()
says:
NOTE: Invoke
addInline
aftersetText(java.lang.String)
; else, mail readers might not be able to resolve inline references correctly.
Upvotes: 12
Reputation: 6624
This works perfectly:
Just add a link to the image hosted on an external server away from your desktop. Use inline CSS, instead of CSS classes.
This website will help you convert CSS classes to inline CSS, Premailer.Dialect.
Avoid any fancy CSS, just use the most basic. Floating (like float: left;) should be avoided as much as possible if you'd like your HTML mail to flow easily, even in mobile devises and other smaller screens.
Include NekoHTML in your project libraries, and change your Spring spring.xml to:
<!-- THYMELEAF: Template Resolver for email templates -->
<bean id="emailTemplateResolver" class="org.thymeleaf.templateresolver.ClassLoaderTemplateResolver">
<property name="prefix" value="resources/WEB_INF/HTMLMailTemplates/XXXX/html/" />
<!-- <property name="templateMode" value="HTML5" /> -->
<property name="templateMode" value="LEGACYHTML5" />
<property name="characterEncoding" value="UTF-8" />
<property name="order" value="1" />
</bean>
Sample this:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Email With Inline Images</title>
<style>
body {
background-image: url('https://dl.dropbox.com/s/XXXX/pageBackGround.gif');
background-repeat: repeat;
margin:0;
outline:0;
}
.pageContentWrapper {
padding:10px;
width: 100%;
background-image: url('https://dl.dropbox.com/s/XXXX/smallerInlineImage.gif');
background-repeat: repeat;
}
.smallerInlineImage {
width: 22px;
height: 22px;
padding: 0 4px 6px 0;
float: left;
}
</style>
</head>
<body>
<div class="pageContentWrapper">
<div class="smallerInlineImage">
<img src="https://dl.dropboxusercontent.com/s/3ydel6zp53pb65b/smallerInlineImage.png" height="22" width="22">
</div>
</div>
</body>
Service Class:
@Service
public class ThymeEmailService {
@Autowired
private JavaMailSender mailSender;
@Autowired
private TemplateEngine templateEngine;
public void sendMailWithInline() throws MessagingException {
final Context ctx = new Context();
final MimeMessage mimeMessage = this.mailSender.createMimeMessage();
final MimeMessageHelper message = new MimeMessageHelper(mimeMessage, true, "UTF-8");
message.setSubject("Sample Email Subject");
message.setFrom("[email protected]");
message.setTo("[email protected]");
final String htmlContent = this.templateEngine.process("emailTemplate.html", ctx);
message.setText(htmlContent, true);
String[] attachments = {"C:\\Users\\MyPc\\Dropbox\\CV\\myPDFAttachment.pdf"};
for (String attachment : attachments) {
FileSystemResource file = new FileSystemResource(attachment);
message.addAttachment(file.getFilename(), file);
}
this.mailSender.send(mimeMessage);
}
}
Upvotes: 1