How to embed images inline in JavaMail instead of sending as attachments using Mailgun SMTP

I’m new to Java programming and working on an email client application. I have a JTextPane where users can insert images, but when I send emails through Mailgun’s SMTP service, the images show up as file attachments rather than being embedded directly in the email content.

private static void processImagesForEmail(JTextPane textPane) throws IOException, BadLocationException, URISyntaxException {
    HTMLDocument document = (HTMLDocument) textPane.getDocument();
    ElementIterator iter = new ElementIterator(document);
    Element elem;

    // Find and process image elements
    List<File> attachedImages = new ArrayList<>();
    while ((elem = iter.next()) != null) {
        AttributeSet attributes = elem.getAttributes();
        Object tagName = attributes.getAttribute(StyleConstants.NameAttribute);

        if (tagName instanceof HTML.Tag) {
            HTML.Tag htmlTag = (HTML.Tag) tagName;

            if (htmlTag == HTML.Tag.IMG) {
                String imageSrc = (String) attributes.getAttribute(HTML.Attribute.SRC);
                if (imageSrc != null && imageSrc.startsWith("file:///")) {
                    // Convert image to base64
                    InputStream stream = new URL(imageSrc).openStream();
                    byte[] data = stream.readAllBytes();
                    String encodedImage = Base64.getEncoder().encodeToString(data);

                    // Update the src with base64 data
                    String updatedSrc = "data:image/png;base64," + encodedImage;
                    document.setInnerHTML(elem, "<img src=\"" + updatedSrc + "\">")

                    // Store file reference
                    String path = new URI(imageSrc).getPath();
                    attachedImages.add(new File(path));
                }
            }
        }
    }
}

Here’s my email sending logic:

public class EmailSender {
    private static void deliverEmail(String recipient, String emailSubject, String htmlContent, List<File> pictures) throws IOException, MessagingException {
        final String user = "";
        final String pass = "";
        Properties config = new Properties();
        config.put("mail.smtp.auth", "true");
        config.put("mail.smtp.starttls.enable", "true");
        config.put("mail.smtp.host", "smtp.mailgun.com");
        config.put("mail.smtp.port", "587");

        Session mailSession = Session.getInstance(config, new javax.mail.Authenticator() {
            protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication(user, pass);
            }
        });
        
        MimeMultipart parts = new MimeMultipart("related");
        
        try {
            for (File picture : pictures) {
                MimeBodyPart imgPart = new MimeBodyPart();
                DataSource source = new FileDataSource(picture);
                imgPart.setDataHandler(new DataHandler(source));
                imgPart.setHeader("Content-ID", "<picture>");
                imgPart.setDisposition(MimeBodyPart.INLINE);
                imgPart.setFileName(picture.getName());
                parts.addBodyPart(imgPart);
            }
            
            MimeMessage email = new MimeMessage(mailSession);
            email.setFrom(new InternetAddress(user));
            email.addRecipient(Message.RecipientType.TO, new InternetAddress(recipient));
            email.setSubject(emailSubject);
            email.setContent(parts);
            
            Transport.send(email);
            JOptionPane.showMessageDialog(null, "Message delivered successfully.");
        } catch (MessagingException ex) {
            JOptionPane.showMessageDialog(null, "Delivery failed: " + ex.getMessage());
            ex.printStackTrace();
        }
    }
}

I tried using base64 encoding and MimeBodyPart with INLINE disposition, but the images still appear as attachments instead of being embedded in the email body. What am I missing to make the images display inline within the email content?

Mailgun SMTP gets weird with inline images. You’re missing the HTML body part completely - that’s why your images show up as attachments instead of inline. Add this before your image parts: MimeBodyPart htmlPart = new MimeBodyPart(); htmlPart.setContent(htmlContent, "text/html"); parts.addBodyPart(htmlPart); Also ditch the base64 approach and just use CID references in your HTML like <img src="cid:picture">.

You’re not adding the HTML content to your email - that’s the problem. You’ve got the multipart structure for attachments but you’re missing the HTML body part that actually references those images. Create a MimeBodyPart for your HTML content and add it to the multipart before the image parts. I hit this same issue last year building a newsletter system. Here’s what you need to do: reference the images in your HTML using the Content-ID headers you’re already setting. Swap out those base64 data URLs for cid references like <img src="cid:picture">. Then create an HTML body part with htmlPart.setContent(htmlContent, "text/html") and add it to your multipart first, then the image parts. The images will display inline instead of as attachments because the email client can match the cid references to the embedded parts.

Had this exact issue building a newsletter tool. You’re converting images to base64 in your HTML but then trying to add them as separate MIME parts - can’t do both. Either stick with base64 or use proper inline embedding with Content-IDs. For the Content-ID route: skip the base64 conversion and replace those data URLs with cid:image_ + some unique ID for each image. In your email code, set matching Content-ID headers on each image part. Most important - add your HTML as the first body part in the multipart. Right now you’re only adding image parts with no HTML body to actually display them. Multipart related only works when your HTML references the attached parts through their Content-IDs.