使用 JavaMail 在电子邮件中嵌入图像

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2996514/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 15:23:24  来源:igfitidea点击:

Inline images in email using JavaMail

javamimemime-typesjavamailmultipart

提问by akula1001

I want to send an email with an inline image using javamail.

我想使用 javamail 发送带有内嵌图像的电子邮件。

I'm doing something like this.

我正在做这样的事情。

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

I've also tried

我也试过

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

and

    bodyPart.setDisposition("inline");

but no matter what, the image is being sent as an attachment and the Content-Dispostion is turning into "attachment".

但无论如何,图像是作为附件发送的,内容处理正在变成“附件”。

How do I send an image inline in the email using javamail?

如何使用 javamail 在电子邮件中内联发送图像?

回答by Bernardo

Why don't you try something like this?

你为什么不尝试这样的事情?

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

in the message, have a <img src="image.jpg"/> tag and you should be ok.

在消息中,有一个 <img src="image.jpg"/> 标签,你应该没问题。

Good Luck

祝你好运

回答by J?rg Pfründer

This worked for me:

这对我有用:

  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;

回答by user1517878

Below is the complete Code

下面是完整的代码

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

回答by Ujjwal Singh

Use the following snippet:

使用以下代码段:

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

You need not in-line & base encode - you can attach traditionally and add the link to the main message's text which is of type text/html.
However remember to set the imgBodyPart's header's Content-Typeto image/jpgor so right before appending to the main message (after you have attached the file).

您不需要内联和基本编码 - 您可以按传统方式附加并将链接添加到类型为 的主消息文本text/html
不过记得要设置imgBodyPart的标题是Content-Typeimage/jpg左右向右附加到主消息(您所附加的文件之后)。

回答by snooze92

Your problem

你的问题

As far as I can see, it looks like the way you create the message and everything is mostly right! You use the right MIME types and everything.

据我所知,它看起来像您创建消息的方式,并且一切都基本正确!您使用正确的 MIME 类型和所有内容。

I am not sure why you use a DataSource and DataHandler, and have a ContentID on the image, but you need to complete your question for me to be able to troubleshoot more. Especially, the following line:

我不确定您为什么使用 DataSource 和 DataHandler,并在图像上有一个 ContentID,但是您需要完成您的问题,以便我能够进行更多故障排除。特别是,以下行:

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

What is in message? Does it contains <img src="cid:image" />?

什么在message?它包含<img src="cid:image" />?

Did you try to generate the ContentID with String cid = ContentIdGenerator.getContentId();instead of using image

您是否尝试使用String cid = ContentIdGenerator.getContentId();而不是使用来生成 ContentIDimage



Source

来源

This blog article taught me how to use the right message type, attach my image and refer to the attachment from the HTML body: How to Send Email with Embedded Images Using Java

这篇博客文章教我如何使用正确的消息类型、附加我的图像并参考 HTML 正文中的附件:如何使用 Java 发送带有嵌入图像的电子邮件



Details

细节

Message

信息

You have to create your content using the MimeMultipartclass. It is important to use the string "related"as a parameter to the constructor, to tell JavaMail that your parts are "working together".

您必须使用MimeMultipart该类创建您的内容。使用字符串"related"作为构造函数的参数很重要,以告诉 JavaMail 您的部分正在“协同工作”

MimeMultipart content = new MimeMultipart("related");

Content identifier

内容标识符

You need to generate a ContentID, it is a string used to identify the image you attached to your email and refer to it from the email body.

您需要生成一个 ContentID,它是一个字符串,用于标识您附加到电子邮件中的图像并从电子邮件正文中引用它。

String cid = ContentIdGenerator.getContentId();

Note: This ContentIdGeneratorclass is hypothetical. You could create one or inline the creation of content IDs. In my case, I use a simple method:

注意:这个ContentIdGenerator类是假设的。您可以创建一个或内联内容 ID 的创建。就我而言,我使用一个简单的方法:

import java.util.UUID;

// ...

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

HTML body

HTML 正文

The HTML code is one part of the MimeMultipartcontent. Use the MimeBodyPartclass for that. Don't forget to specify the encodingand "html"when you set the text of that part!

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

Note that as a source of the image, we use cid:and the generated ContentID.

请注意,作为图像的来源,我们使用cid:和生成的 ContentID。

Image attachment

图片附件

We can create another MimeBodyPartfor the attachment of the image.

我们可以MimeBodyPart为图像的附件创建另一个。

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

Note that we use the same ContentID between <and >and set it as the image's ContentID. We also set the disposition to INLINEto signal that this image is meant to be displayed in the email, not as an attachment.

请注意,我们在<和之间使用相同的 ContentID ,>并将其设置为图像的 ContentID。我们还将处置设置INLINE为表明此图像将显示在电子邮件中,而不是作为附件显示。

Finish message

完成留言

That's it! If you create an SMTP message on the right session and use that content, your email will contain an embedded image! For instance:

就是这样!如果您在正确的会话中创建 SMTP 消息并使用该内容,您的电子邮件将包含嵌入的图像!例如:

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)

Let me know if that works for you! ;)

让我知道这是否适合您!;)

回答by Ankur Mahajan

If you are using Springuse MimeMessageHelperto send email with inline content (References).

如果您使用的春天使用MimeMessageHelper,以发送带有内嵌的内容(电子邮件参考)。

Create JavaMailSenderbean or configure this by adding corresponding properties to application.properties file, if you are using Spring Boot.

如果您使用的是Spring Boot,则创建JavaMailSenderbean 或通过向 application.properties 文件添加相应的属性来配置它。

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

Create algorithm to generate unique CONTENT-ID

创建算法以生成唯一的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;
    }

}

Send Email with inlines.

使用内联发送电子邮件。

@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());
    }

}

回答by debbbole

I had some problems having inline images displayed in GMail and Thunderbird, made some tests and resolved with the following (sample) code:

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

Just some things to notice:

只是一些注意事项:

  • the "Content-ID" has to be built as specified in the RFCs (https://tools.ietf.org/html/rfc2392), so it has to be the part in the img tag src attribute, following the "cid:", enclosed by angle brackets ("<" and ">")
  • I had to set the file name
  • no need for width, height, alt or title in the img tag
  • I had to put the charset that way, because the one in the html was being ignored
  • “Content-ID”必须按照 RFC ( https://tools.ietf.org/html/rfc2392)中的规定构建,因此它必须是 img 标签 src 属性中的一部分,在“cid: ",用尖括号括起来(“<”和“>”)
  • 我必须设置文件名
  • img 标签中不需要宽度、高度、alt 或标题
  • 我不得不这样放置字符集,因为 html 中的字符集被忽略了

This worked for me making inline images display for some clients and in GMail web client, I don't mean this will work everywhere and forever! :)

这对我有用,可以为某些客户端和 GMail 网络客户端显示内联图像,我并不是说这将在任何地方和永远有效!:)

(Sorry for my english and for my typos!)

(对不起,我的英语和我的错别字!)

回答by Hymanie Yu

RFC Specification could be found here(https://tools.ietf.org/html/rfc2392).

RFC 规范可以在这里找到(https://tools.ietf.org/html/rfc2392)。

Firstly, email html content needs to format like : "cid:logo.png" when using inline pictures, see:

首先,使用内联图片时,电子邮件 html 内容需要格式为:“cid:logo.png”,参见:

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

Secondly, MimeBodyPart object needs to set property "disposition" as MimeBodyPart.INLINE, as below:

其次,MimeBodyPart 对象需要设置属性“disposition”为MimeBodyPart.INLINE,如下:

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

Be aware, Content-ID property must prefix and suffix with "<" and ">" perspectively, and the value off filename should be same with the content of src of img tag without prefix "cid:"

请注意,Content-ID 属性必须以“<”和“>”作为前缀和后缀,并且filename 的值应与没有前缀“cid:”的img 标签的src 内容相同

Finally the whole code is below:

最后整个代码如下:

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