JavaMail embedded images showing as attachments instead of inline content in email

Hey everyone! I’m pretty new to Java development and I’ve run into a problem that’s got me stumped. I’m working on an email application that uses a JEditorPane where users can add images to their messages. The issue is that when I send the email, the images show up as file attachments rather than being displayed inline within the email body.

private static void processImagesInEmail(JEditorPane textPane) throws IOException, BadLocationException, URISyntaxException {
    HTMLDocument document = (HTMLDocument) textPane.getDocument();
    ElementIterator elemIterator = new ElementIterator(document);
    Element currentElement;

    // Find and process images for embedding
    List<File> imagesToEmbed = new ArrayList<>();
    while ((currentElement = elemIterator.next()) != null) {
        AttributeSet attributes = currentElement.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[] imageBytes = stream.readAllBytes();
                    String encodedImage = Base64.getEncoder().encodeToString(imageBytes);

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

                    // Store file for email processing
                    String pathToFile = new URI(imageSrc).getPath();
                    imagesToEmbed.add(new File(pathToFile));
                }
            }
        }
    }
}

I tried using base64 encoding even though I know MimeBodyPart is usually better. Here’s my email sending code that’s supposed to embed the images but still results in attachments:

public class EmailSender {
    private static void setupInterface() {
        JFrame mainFrame = new JFrame("Email Client");
        mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        mainFrame.setSize(1200, 800);
        
        // Image insertion handler
        addImageBtn.addActionListener(e -> {
            JFileChooser chooser = new JFileChooser();
            chooser.setFileFilter(new FileNameExtensionFilter("Image Files", "jpg", "jpeg", "png", "gif"));
            if (chooser.showOpenDialog(mainFrame) == JFileChooser.APPROVE_OPTION) {
                File selectedImage = chooser.getSelectedFile();
                addImageToPane(textPane, selectedImage);
            }
        });
        
        JButton mailButton = new JButton("Send Message");
        mailButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                String recipient = recipientField.getText();
                String mailSubject = subjectField.getText();
                String mailContent = "<html><body>" + textPane.getText() + "</body></html>";
                
                if (recipient.isEmpty() || mailSubject.isEmpty() || mailContent.isEmpty()) {
                    JOptionPane.showMessageDialog(mainFrame, "All fields must be filled.");
                    return;
                }

                try {
                    dispatchEmail(recipient, mailSubject, mailContent, imageFileList);
                } catch (IOException | MessagingException ex) {
                    ex.printStackTrace();
                }
            }
        });
    }

    private static void dispatchEmail(String recipient, String mailSubject, String mailContent, List<File> imageFileList) 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 messageContent = new MimeMultipart("related");
        
        try {
            for (File imageFile : imageFileList) {
                MimeBodyPart imageSection = new MimeBodyPart();
                DataSource dataSource = new FileDataSource(imageFile);
                imageSection.setDataHandler(new DataHandler(dataSource));
                imageSection.setHeader("Content-ID", "<image>");
                imageSection.setDisposition(MimeBodyPart.INLINE);
                imageSection.setFileName(imageFile.getName());
                messageContent.addBodyPart(imageSection);
            }
            
            MimeMessage emailMessage = new MimeMessage(mailSession);
            emailMessage.setFrom(new InternetAddress(user));
            emailMessage.addRecipient(Message.RecipientType.TO, new InternetAddress(recipient));
            emailMessage.setSubject(mailSubject);
            emailMessage.setContent(messageContent);

            Transport.send(emailMessage);
            JOptionPane.showMessageDialog(null, "Message sent successfully.");
        } catch (MessagingException ex) {
            JOptionPane.showMessageDialog(null, "Failed to send message: " + ex.getMessage());
            ex.printStackTrace();
        }
    }
}

I’m really stuck on this and would appreciate any help or suggestions you can offer!

you’re missing the html body part in your multipart message. the images are getting added, but there’s no html content that actually references them with cid: tags. add a MimeBodyPart for your html content before the image parts, and make sure your img tags use cid:imagename format instead of base64.

Your HTML content construction is the problem. You’re setting multipart content directly on the message, but your HTML body isn’t actually part of that multipart structure. You need to add the HTML content as its own MimeBodyPart within the multipart container.

Create a MimeBodyPart for your HTML content first, then add it to the multipart before adding the image parts. Your HTML should reference images using Content-ID like <img src="cid:uniqueImageId">. Each image needs a distinct Content-ID that matches what’s in your HTML.

Also, you’re processing the JEditorPane content with base64 encoding, then adding the same images as attachments. Pick one approach - either embed as base64 directly in HTML or use the MimeBodyPart approach with Content-ID references. Don’t do both.

I see the problem right away. You’re adding MimeBodyPart objects for your images to the multipart, but there’s no HTML body part that actually references them. Without an HTML body linking to these images via Content-ID, email clients just treat them as regular attachments.

You need to create a separate MimeBodyPart for your HTML content and add it to the multipart before the image parts. In your HTML, reference the images like this: <img src="cid:image1"> where “image1” matches the Content-ID you set on the image part (minus the angle brackets).

Also, each image needs a unique Content-ID if you’re embedding multiple images. Right now you’re using the same “image” ID for everything, which will break things. Use the filename or a counter to make them unique.