Program-Me-Rev
Program-Me-Rev

Reputation: 6624

How to send email with inline image using ThymeLeaf

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

Answers (3)

skyho
skyho

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>

enter image description here

Upvotes: 0

derickson82
derickson82

Reputation: 496

Just move your call to setText() up a few lines.

The javadoc for MimeMessageHelper.addInLine() says:

NOTE: Invoke addInline after setText(java.lang.String); else, mail readers might not be able to resolve inline references correctly.

Upvotes: 12

Program-Me-Rev
Program-Me-Rev

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

Related Questions