web-dev-qa-db-fra.com

Images en ligne dans les e-mails à l'aide de JavaMail

Je souhaite envoyer un e-mail avec une image en ligne à l'aide de javamail.

Je fais quelque chose comme ça.

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);

J'ai aussi essayé

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

et

    bodyPart.setDisposition("inline");

mais quoi qu'il en soit, l'image est envoyée en pièce jointe et le Content-Dispostion se transforme en "pièce jointe".

Comment envoyer une image en ligne dans l'e-mail à l'aide de javamail?

26
akula1001

Ton problème

Pour autant que je puisse voir, cela ressemble à la façon dont vous créez le message et tout va bien! Vous utilisez les bons types MIME et tout.

Je ne sais pas pourquoi vous utilisez un DataSource et DataHandler, et avez un ContentID sur l'image, mais vous devez répondre à votre question pour que je puisse résoudre plus. Surtout, la ligne suivante:

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

Que contient message? Contient-il <img src="cid:image" />?

Avez-vous essayé de générer le ContentID avec String cid = ContentIdGenerator.getContentId(); au lieu d'utiliser image


La source

Cet article de blog m'a appris à utiliser le bon type de message, à joindre mon image et à se référer à la pièce jointe du corps HTML: Comment envoyer un e-mail avec des images intégrées à l'aide de Java


Détails

Message

Vous devez créer votre contenu en utilisant la classe MimeMultipart . Il est important d'utiliser la chaîne "related" Comme paramètre pour le constructeur, pour indiquer à JavaMail que vos pièces "fonctionnent ensemble" .

MimeMultipart content = new MimeMultipart("related");

Identifiant de contenu

Vous devez générer un ContentID, c'est une chaîne utilisée pour identifier l'image que vous avez jointe à votre e-mail et vous y référer depuis le corps de l'e-mail.

String cid = ContentIdGenerator.getContentId();

Remarque: Cette classe ContentIdGenerator est hypothétique. Vous pouvez en créer un ou incorporer la création d'ID de contenu. Dans mon cas, j'utilise une méthode simple:

import Java.util.UUID;

// ...

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

Corps HTML

Le code HTML est une partie du contenu MimeMultipart . Utilisez la classe MimeBodyPart pour cela. N'oubliez pas de spécifier les encoding et "html" Lorsque vous définissez le texte de cette partie!

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);

Notez que comme source de l'image, nous utilisons cid: Et le ContentID généré.

Attachement d'image

Nous pouvons en créer un autre MimeBodyPart pour l'attachement de l'image.

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

Notez que nous utilisons le même ContentID entre < Et > Et le définissons comme ContentID de l'image. Nous avons également défini la disposition sur INLINE pour signaler que cette image est destinée à être affichée dans l'e-mail, et non en tant que pièce jointe.

Terminer le message

C'est ça! Si vous créez un message SMTP sur la bonne session et utilisez ce contenu, votre e-mail contiendra une image intégrée! Par exemple:

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

Laissez-moi savoir si cela fonctionne pour vous! ;)

33
snooze92

Cela a fonctionné pour moi:

  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
Jörg Pfründer

Pourquoi n'essayez-vous pas quelque chose comme ça?

    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);

dans le message, ayez un <img src="image.jpg"/> tag et ça devrait aller.

Bonne chance

10
Bernardo

Si vous utilisez Spring utilisez MimeMessageHelper pour envoyer des e-mails avec un contenu en ligne ( Références ).

Créez JavaMailSender bean ou configurez-le en ajoutant les propriétés correspondantes au fichier application.properties, si vous utilisez 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;
}

Créer un algorithme pour générer un ID DE CONTENU unique

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;
    }

}

Envoyer un e-mail avec des inscriptions.

@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("[email protected]");
        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());
    }

}
2
Ankur Mahajan

La spécification RFC peut être trouvée ici ( https://tools.ietf.org/html/rfc2392 ).

Tout d'abord, le contenu HTML des e-mails doit être formaté comme: "cid: logo.png" lors de l'utilisation d'images en ligne, voir:

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

Deuxièmement, l'objet MimeBodyPart doit définir la propriété "disposition" comme MimeBodyPart.INLINE, comme ci-dessous:

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

Attention, la propriété Content-ID doit préfixer et suffixer avec "<" et ">" en perspective, et la valeur du nom de fichier doit être identique avec le contenu de src de la balise img sans préfixe "cid : "

Enfin, tout le code est ci-dessous:

Message msg = new MimeMessage(session);
msg.setFrom(new InternetAddress("[email protected]");
InternetAddress[] recipients = { "[email protected]"};
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();
1
Jackie Yu

J'ai eu quelques problèmes d'affichage d'images en ligne dans GMail et Thunderbird, j'ai fait quelques tests et résolu avec le code (exemple) suivant:

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);

Quelques choses à noter:

  • le "Content-ID" doit être construit comme spécifié dans les RFC ( https://tools.ietf.org/html/rfc2392 ), il doit donc faire partie de la balise img src attribut, après le "cid:", entouré de crochets ("<" et ">")
  • J'ai dû définir le nom du fichier
  • pas besoin de largeur, hauteur, alt ou titre dans la balise img
  • J'ai dû mettre le charset de cette façon, car celui du html était ignoré

Cela a fonctionné pour moi en créant des images en ligne pour certains clients et dans le client Web GMail, je ne veux pas dire que cela fonctionnera partout et pour toujours! :)

(Désolé pour mon anglais et pour mes fautes de frappe!)

0
debbbole

Voici le code complet

    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\"/>"
0
user1517878

Utilisez l'extrait de code suivant:

MimeBodyPart imgBodyPart = new MimeBodyPart();
imgBodyPart.attachFile("Image.png");
imgBodyPart.setContentID('<'+"[email protected]"+'>');
imgBodyPart.setDisposition(MimeBodyPart.INLINE);
imgBodyPart.setHeader("Content-Type", "image/png");

multipart.addBodyPart(imgBodyPart);

Vous n'avez pas besoin d'encoder en ligne et en base - vous pouvez joindre traditionnellement et ajouter le lien vers le texte du message principal qui est de type text/html.
Cependant, n'oubliez pas de définir l'en-tête de imgBodyPartContent-Type à image/jpg ou à peu près avant d'ajouter au message principal (après avoir joint le fichier).

0
Ujjwal Singh