Встроенные изображения в электронной почте с использованием JavaMail - PullRequest
25 голосов
/ 08 июня 2010

Я хочу отправить электронное письмо со встроенным изображением, используя javamail.

Я делаю что-то вроде этого.

MimeMultipart content = new MimeMultipart("related");

BodyPart bodyPart = new MimeBodyPart();
bodyPart.setContent(message, "text/html; charset=ISO-8859-1");
content.addBodyPart(bodyPart);

bodyPart = new MimeBodyPart();
DataSource ds = new ByteArrayDataSource(image, "image/jpeg");
bodyPart.setDataHandler(new DataHandler(ds));
bodyPart.setHeader("Content-Type", "image/jpeg; name=image.jpg");
bodyPart.setHeader("Content-ID", "<image>");
bodyPart.setHeader("Content-Disposition", "inline");
content.addBodyPart(bodyPart);

msg.setContent(content);

Я тоже пробовал

    bodyPart.setHeader("inline; filename=image.jpg");

и

    bodyPart.setDisposition("inline");

но, несмотря ни на что, изображение отправляется в виде вложения, а удаление содержимого превращается в «вложение».

Как мне отправить изображение, встроенное в электронное письмо, используя javamail?

Ответы [ 9 ]

32 голосов
/ 07 января 2014

Ваша проблема

Насколько я вижу, похоже, что вы создаете сообщение, и все в основном правильно! Вы используете правильные типы MIME и все.

Я не уверен, почему вы используете DataSource и DataHandler, и у вас есть ContentID на изображении, но вам нужно заполнить свой вопрос, чтобы я мог больше устранять неполадки. Особенно, следующая строка:

bodyPart.setContent(message, "text/html; charset=ISO-8859-1");

Что находится в message? Содержит ли оно <img src="cid:image" />?

Вы пытались сгенерировать ContentID с String cid = ContentIdGenerator.getContentId(); вместо использования image


Источник

Эта статья в блоге научила меня, как использовать правильный тип сообщения, прикрепить мое изображение и обратиться к вложению из тела HTML: Как отправлять электронную почту со встроенными изображениями с использованием Java


Подробнее

Сообщение

Вы должны создать свой контент, используя класс MimeMultipart. Важно использовать строку "related" в качестве параметра для конструктора, чтобы сообщить JavaMail, что ваши части "работают вместе" .

MimeMultipart content = new MimeMultipart("related");

Идентификатор контента

Вам необходимо сгенерировать ContentID, это строка, используемая для идентификации изображения, которое вы прикрепили к своей электронной почте, и ссылки на него в теле письма.

String cid = ContentIdGenerator.getContentId();

Примечание. Этот класс ContentIdGenerator является гипотетическим. Вы можете создать один или встроить создание идентификаторов контента. В моем случае я использую простой метод:

import java.util.UUID;

// ...

String generateContentId(String prefix) {
     return String.format("%s-%s", prefix, UUID.randomUUID());
}

HTML body

HTML-код является частью содержимого MimeMultipart. Для этого используйте класс MimeBodyPart. Не забудьте указать encoding и "html" при настройке текста этой части!

MimeBodyPart htmlPart = new MimeBodyPart();
htmlPart.setText(""
  + "<html>"
  + " <body>"
  + "  <p>Here is my image:</p>"
  + "  <img src=\"cid:" + cid + "\" />"
  + " </body>"
  + "</html>" 
  ,"US-ASCII", "html");
content.addBodyPart(htmlPart);

Обратите внимание, что в качестве источника изображения мы используем cid: и сгенерированный ContentID.

Вложение изображения

Мы можем создать еще один MimeBodyPart для прикрепления изображения.

MimeBodyPart imagePart = new MimeBodyPart();
imagePart.attachFile("resources/teapot.jpg");
imagePart.setContentID("<" + cid + ">");
imagePart.setDisposition(MimeBodyPart.INLINE);
content.addBodyPart(imagePart);

Обратите внимание, что мы используем один и тот же ContentID между < и > и устанавливаем его в качестве ContentID изображения. Мы также установили расположение на INLINE, чтобы сигнализировать, что это изображение предназначено для отображения в электронном письме, а не в качестве вложения.

Завершить сообщение

Вот и все! Если вы создадите SMTP-сообщение в нужный сеанс и будете использовать этот контент, ваша электронная почта будет содержать встроенное изображение! Например:

SMTPMessage m = new SMTPMessage(session);
m.setContent(content);
m.setSubject("Mail with embedded image");
m.setRecipient(RecipientType.TO, new InternetAddress("your@email.com"));
Transport.send(m)

Дайте мне знать, если это работает для вас! ;)

10 голосов
/ 07 июня 2011

Это сработало для меня:

  MimeMultipart rootContainer = new MimeMultipart();
  rootContainer.setSubType("related"); 
  rootContainer.addBodyPart(alternativeMultiPartWithPlainTextAndHtml); // not in focus here
  rootContainer.addBodyPart(createInlineImagePart(base64EncodedImageContentByteArray));
  ...
  message.setContent(rootContainer);
  message.setHeader("MIME-Version", "1.0");
  message.setHeader("Content-Type", rootContainer.getContentType());

  ...


  BodyPart createInlineImagePart(byte[] base64EncodedImageContentByteArray) throws MessagingException {
    InternetHeaders headers = new InternetHeaders();
    headers.addHeader("Content-Type", "image/jpeg");
    headers.addHeader("Content-Transfer-Encoding", "base64");
    MimeBodyPart imagePart = new MimeBodyPart(headers, base64EncodedImageContentByteArray);
    imagePart.setDisposition(MimeBodyPart.INLINE);
    imagePart.setContentID("&lt;image&gt;");
    imagePart.setFileName("image.jpg");
    return imagePart;
10 голосов
/ 10 сентября 2010

Почему бы тебе не попробовать что-нибудь подобное?

    MimeMessage mail =  new MimeMessage(mailSession);

    mail.setSubject(subject);

    MimeBodyPart messageBodyPart = new MimeBodyPart();

    messageBodyPart.setContent(message, "text/html");

    Multipart multipart = new MimeMultipart();
    multipart.addBodyPart(messageBodyPart);

    messageBodyPart = new MimeBodyPart();
    DataSource source = new FileDataSource(new File("complete path to image.jpg"));
    messageBodyPart.setDataHandler(new DataHandler(source));
    messageBodyPart.setFileName(fileAttachment.getName());
    messageBodyPart.setDisposition(MimeBodyPart.INLINE);
    multipart.addBodyPart(messageBodyPart);

    mail.setContent(multipart);

в сообщении есть <img src="image.jpg"/> тег, и вы должны быть в порядке.

Удачи

2 голосов
/ 09 апреля 2018

Если вы используете Spring , используйте MimeMessageHelper для отправки электронной почты со встроенным содержимым ( Ссылки ).

Создание JavaMailSender bean или настройте это, добавив соответствующие свойства в файл application.properties, если вы используете Spring Boot .

@Bean
public JavaMailSender getJavaMailSender() {
    JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
    mailSender.setHost(host);
    mailSender.setPort(port);
    mailSender.setUsername(username);
    mailSender.setPassword(password);
    Properties props = mailSender.getJavaMailProperties();
    props.put("mail.transport.protocol", "smtp");
    props.put("mail.smtp.auth", authEnable);
    props.put("mail.smtp.starttls.enable", starttlsEnable);
    //props.put("mail.debug", "true");
    mailSender.setJavaMailProperties(props);
    return mailSender;
}

Создайте алгоритм для генерации уникального CONTENT-ID

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Random;

public class ContentIdGenerator {

    static int seq = 0;
    static String hostname;

    public static void getHostname() {
        try {
            hostname = InetAddress.getLocalHost().getCanonicalHostName();
        }
        catch (UnknownHostException e) {
            // we can't find our hostname? okay, use something no one else is
            // likely to use
            hostname = new Random(System.currentTimeMillis()).nextInt(100000) + ".localhost";
        }
    }

    /**
     * Sequence goes from 0 to 100K, then starts up at 0 again. This is large
     * enough,
     * and saves
     * 
     * @return
     */
    public static synchronized int getSeq() {
        return (seq++) % 100000;
    }

    /**
     * One possible way to generate very-likely-unique content IDs.
     * 
     * @return A content id that uses the hostname, the current time, and a
     *         sequence number
     *         to avoid collision.
     */
    public static String getContentId() {
        getHostname();
        int c = getSeq();
        return c + "." + System.currentTimeMillis() + "@" + hostname;
    }

}

Отправить электронное письмо со строками.

@Autowired
private JavaMailSender javaMailSender;

public void sendEmailWithInlineImage() {
    MimeMessage mimeMessage = null;
    try {
        InternetAddress from = new InternetAddress(from, personal);
        mimeMessage = javaMailSender.createMimeMessage();
        mimeMessage.setSubject("Test Inline");
        MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
        helper.setFrom(from);
        helper.setTo("test@test.com");
        String contentId = ContentIdGenerator.getContentId();
        String htmlText = "Hello,</br> <p>This is test with email inlines.</p><img src=\"cid:" + contentId + "\" />";
        helper.setText(htmlText, true);

        ClassPathResource classPathResource = new ClassPathResource("static/images/first.png");
        helper.addInline(contentId, classPathResource);
        javaMailSender.send(mimeMessage);
    }
    catch (Exception e) {
        LOGGER.error(e.getMessage());
    }

}
0 голосов
/ 26 апреля 2019

RFC Спецификация может быть найдена здесь (https://tools.ietf.org/html/rfc2392).

Во-первых, html-содержимое электронной почты должно форматироваться следующим образом: "cid: logo.png" при использовании встроенных изображений, см .:

<td style="width:114px;padding-top: 19px">
    <img src="cid:logo.png" />
</td>

Во-вторых, объект MimeBodyPart должен установить свойство «disposition» как MimeBodyPart.INLINE, как показано ниже:

String filename = "logo.png"
BodyPart image = new MimeBodyPart();
image.setDisposition(MimeBodyPart.INLINE);
image.setFileName(filename);
image.setHeader("Content-ID", "<" +filename+">");

Имейте в виду, свойство Content-ID должно иметь префикс и суффикс с "<" и ">" в перспективе, а значение off имя файла должно совпадать с содержимым src тега img без префикса "cid:"

Наконец, весь код ниже:

Message msg = new MimeMessage(session);
msg.setFrom(new InternetAddress("1234@gmail.com");
InternetAddress[] recipients = { "123@gmail.com"};
msg.setRecipients(Message.RecipientType.TO, recipients);
msg.setSubject("for test");
msg.setSentDate(new Date());

BodyPart content = new MimeBodyPart();
content.setContent(<html><body>  <img src="cid:logo.png" /> </body></html>, "text/html; charset=utf-8");
String fileName = "logo.png";
BodyPart image = new MimeBodyPart();
image.setHeader("Content-ID", "<" +fileName+">");
image.setDisposition(MimeBodyPart.INLINE);
image.setFileName(fileName);
InputStream stream = MailService.class.getResourceAsStream(path);
DataSource fds = new ByteArrayDataSource(IOUtils.toByteArray(stream), "image/png");
image.setDataHandler(new DataHandler(fds));

MimeMultipart multipart = new MimeMultipart("related");
multipart.addBodyPart(content);
multipart.addBodyPart(getImage(image1));
msg.setContent(multipart);
msg.saveChanges();
Transport bus = session.getTransport("smtp");
bus.connect("username", "password");
bus.sendMessage(msg, recipients);
bus.close();
0 голосов
/ 08 апреля 2019

У меня были некоторые проблемы с отображением встроенных изображений в GMail и Thunderbird, я провел несколько тестов и решил следующий (пример) код:

String imagePath = "/path/to/the/image.png";
String fileName = imagePath.substring(path.lastIndexOf('/') + 1);
String htmlText = "<html><body>TEST:<img src=\"cid:img1\"></body></html>";
MimeMultipart multipart = new MimeMultipart("related");
BodyPart messageBodyPart = new MimeBodyPart();
messageBodyPart.setContent(htmlText, "text/html; charset=utf-8");
multipart.addBodyPart(messageBodyPart);
messageBodyPart = new MimeBodyPart();
DataSource fds = new FileDataSource(imagePath);
messageBodyPart.setDataHandler(new DataHandler(fds));
messageBodyPart.setHeader("Content-ID", "<img1>");
messageBodyPart.setDisposition(MimeBodyPart.INLINE);
messageBodyPart.setFileName(fileName);
multipart.addBodyPart(messageBodyPart);
message.setContent(multipart);

Только некоторые вещи, на которые стоит обратить внимание:

  • «Content-ID» должен быть построен, как указано в RFC (https://tools.ietf.org/html/rfc2392),, поэтому он должен быть частью атрибута src тега img, после «cid:», заключенного в угловые скобки ("<" и ">")
  • Я должен был установить имя файла
  • не нужно указывать ширину, высоту, альт или заголовок в теге img
  • Я должен был поставить кодировку таким образом, потому что тот в html игнорировался

Это помогло мне сделать отображение встроенных изображений для некоторых клиентов и в веб-клиенте GMail, я не имею в виду, что это будет работать везде и всегда! :)

(Извините за мой английский и за опечатки!)

0 голосов
/ 26 апреля 2018

messageBodyPart.setContent (htmlText, "text / html"); multipart.addBodyPart (messageBodyPart);

        messageBodyPart = new MimeBodyPart();
        DataSource fds = new FileDataSource("resources/Images/bday.jpg");

         messageBodyPart.setDataHandler(new DataHandler(fds));
         messageBodyPart.setHeader("Content-ID", "<image>");

         // add image to the multipart
         multipart.addBodyPart(messageBodyPart);

         msg.setContent(multipart);

        Transport.send(msg);
0 голосов
/ 17 декабря 2013

Используйте следующий фрагмент:

MimeBodyPart imgBodyPart = new MimeBodyPart();
imgBodyPart.attachFile("Image.png");
imgBodyPart.setContentID('<'+"i01@example.com"+'>');
imgBodyPart.setDisposition(MimeBodyPart.INLINE);
imgBodyPart.setHeader("Content-Type", "image/png");

multipart.addBodyPart(imgBodyPart);

Вам не нужно in-line и basecode - вы можете присоединить его традиционно и добавить ссылку на текст основного сообщения типа text/html.
Однако не забудьте установить Content-Type заголовок *1007* на image/jpg или около того прямо перед добавлением к основному сообщению (после того, как вы прикрепили файл).

0 голосов
/ 20 июля 2013

Ниже приведен полный код

    import java.awt.image.BufferedImage;
    import java.io.ByteArrayInputStream;
    import java.io.ByteArrayOutputStream;
    import java.io.File;
    import java.io.IOException;
    import javax.imageio.ImageIO;

    private BodyPart createInlineImagePart()  {
    MimeBodyPart imagePart =null;
    try
    {

        ByteArrayOutputStream baos=new ByteArrayOutputStream(10000);
        BufferedImage img=ImageIO.read(new File(directory path,"sdf_email_logo.jpg"));
        ImageIO.write(img, "jpg", baos);
        baos.flush();

        String base64String=Base64.encode(baos.toByteArray());
        baos.close();

        byte[] bytearray = Base64.decode(base64String);
        InternetHeaders headers = new InternetHeaders();
        headers.addHeader("Content-Type", "image/jpeg");
        headers.addHeader("Content-Transfer-Encoding", "base64");
        imagePart = new MimeBodyPart(headers, bytearray);
        imagePart.setDisposition(MimeBodyPart.INLINE);
        imagePart.setContentID("&lt;sdf_email_logo&gt;");
        imagePart.setFileName("sdf_email_logo.jpg");
    }
    catch(Exception exp)
    {
        logError("17", "Logo Attach Error : "+exp);
    }

    return imagePart;
}


MimeMultipart mp = new MimeMultipart();
 //mp.addBodyPart(createInlineImagePart());

mp.addBodyPart(createInlineImagePart());

String body="<img src=\"cid:sdf_email_logo\"/>"
...