基于Java Mail API提取邮件正文内嵌图片并存储至数据库
Got it, let's tackle extracting inline images from your email body and saving them to a database. Your existing methods already handle attachments and text content, so we can extend those to capture inline images without breaking what's already working.
Step 1: Create a Class to Store Inline Image Metadata
First, we need a simple way to hold all critical details of an inline image for database storage. This includes its unique content ID (used to reference it in the HTML body), filename, content type, and raw image data:
public class InlineImage { private String contentId; // Matches the `cid:` value in <img> tags private String fileName; private String contentType; // e.g., "image/png", "image/jpeg" private byte[] data; // The raw image bytes // Constructor and getters public InlineImage(String contentId, String fileName, String contentType, byte[] data) { this.contentId = contentId; this.fileName = fileName; this.contentType = contentType; this.data = data; } public String getContentId() { return contentId; } public String getFileName() { return fileName; } public String getContentType() { return contentType; } public byte[] getData() { return data; } }
Step 2: Create a Result Wrapper for Content + Images
Since we need to return both the email body and the list of inline images, let's make a wrapper class to bundle these together cleanly:
public class EmailContentResult { private String content; private List<InlineImage> inlineImages; public EmailContentResult(String content, List<InlineImage> inlineImages) { this.content = content; this.inlineImages = inlineImages; } public String getContent() { return content; } public List<InlineImage> getInlineImages() { return inlineImages; } }
Step 3: Update Content Extraction to Capture Inline Images
Let's modify your existing getContent method to collect inline images while extracting the body content. We'll keep your original text-handling logic intact and add image extraction for inline parts:
public static EmailContentResult getContentWithInlineImages(MimeMultipart multipart) { String emailContent = ""; List<InlineImage> inlineImages = new ArrayList<>(); if (multipart != null) { try { for (int i = 0; i < multipart.getCount(); i++) { MimeBodyPart currentPart = (MimeBodyPart) multipart.getBodyPart(i); // Handle nested multipart sections first (recursive call) if (currentPart.getContent() instanceof MimeMultipart) { EmailContentResult nestedResult = getContentWithInlineImages((MimeMultipart) currentPart.getContent()); emailContent += nestedResult.getContent(); inlineImages.addAll(nestedResult.getInlineImages()); continue; } String disposition = currentPart.getDisposition(); String contentType = currentPart.getContentType().toLowerCase(); // Case 1: Inline content (could be text or image) if (Part.INLINE.equalsIgnoreCase(disposition)) { if (contentType.startsWith("image/")) { // Extract inline image details String contentId = currentPart.getContentID(); // Clean up content ID (some servers wrap it in <>) if (contentId != null && contentId.startsWith("<") && contentId.endsWith(">")) { contentId = contentId.substring(1, contentId.length() - 1); } String fileName = currentPart.getFileName(); byte[] imageData = IOUtils.toByteArray(currentPart.getInputStream()); inlineImages.add(new InlineImage(contentId, fileName, contentType, imageData)); LoggerFactory.getLogger(EmailUtil.class.getName()) .info("Collected inline image with CID: {}", contentId); } else { // Capture inline text/html content try { emailContent += currentPart.getContent(); } catch (ClassCastException ex) { InputStream is = currentPart.getInputStream(); emailContent += IOUtils.toString(is, currentPart.getEncoding()); } } } // Case 2: Non-disposition text content (your original logic) else if (disposition == null && contentType.contains("text")) { try { emailContent += currentPart.getContent(); } catch (ClassCastException ex) { InputStream is = currentPart.getInputStream(); emailContent += IOUtils.toString(is, currentPart.getEncoding()); // Keep your Jsoup HTML cleanup if needed Document doc = Jsoup.parse(emailContent); Elements imgTags = doc.getElementsByTag("img"); LoggerFactory.getLogger(EmailUtil.class.getName()) .info("Found {} img tags in HTML content", imgTags.size()); } } } } catch (MessagingException | IOException ex) { LoggerFactory.getLogger(EmailUtil.class.getName()).error("Failed to extract email content: {}", ex.getMessage()); } } return new EmailContentResult(emailContent, inlineImages); }
Step 4: Save Inline Images to the Database
Once you have the list of InlineImage objects, saving them to a database is straightforward. Here's a JDBC example (adjust for your ORM like Hibernate if you use one):
public static void saveInlineImagesToDB(List<InlineImage> inlineImages) { String sql = "INSERT INTO inline_images (content_id, file_name, content_type, image_data) VALUES (?, ?, ?, ?)"; try (Connection conn = DriverManager.getConnection("your-db-url", "user", "password"); PreparedStatement pstmt = conn.prepareStatement(sql)) { for (InlineImage img : inlineImages) { pstmt.setString(1, img.getContentId()); pstmt.setString(2, img.getFileName()); pstmt.setString(3, img.getContentType()); pstmt.setBytes(4, img.getData()); pstmt.addBatch(); } pstmt.executeBatch(); LoggerFactory.getLogger(EmailUtil.class.getName()) .info("Saved {} inline images to database", inlineImages.size()); } catch (SQLException ex) { LoggerFactory.getLogger(EmailUtil.class.getName()).error("Failed to save inline images: {}", ex.getMessage()); } }
Key Details to Note
- Content ID Matching: The
contentIdfield directly maps to thecid:value in your HTML<img>tags (e.g.,<img src="cid:my-image-123">links to anInlineImagewithcontentId = "my-image-123"). This lets you retrieve the correct image later when rendering the HTML. - Nested Multipart Support: The recursive logic ensures we capture inline images even if they're buried inside nested multipart sections.
- Cleanup: We strip
<>around content IDs (some email servers add these) to ensure proper matching with HTML img tags.
How to Use the Updated Code
Replace your existing getContent call with this new method, then save the images:
MimeMultipart emailMultipart = ...; // Your incoming email multipart object EmailContentResult result = EmailUtil.getContentWithInlineImages(emailMultipart); // Use the extracted email body String emailBody = result.getContent(); // Save inline images to your database EmailUtil.saveInlineImagesToDB(result.getInlineImages());
内容的提问来源于stack exchange,提问作者Rajan jha

