\n");
if (content.getHtmlBody() != null && !content.getHtmlBody().trim().isEmpty()) {
- html.append(processEmailHtmlBody(content.getHtmlBody()));
+ html.append(processEmailHtmlBody(content.getHtmlBody(), content));
} else if (content.getTextBody() != null && !content.getTextBody().trim().isEmpty()) {
html.append("
");
html.append(convertTextToHtml(content.getTextBody()));
@@ -1039,7 +1142,7 @@ public class EmlToPdf {
.append(uniqueId)
.append("\">")
.append("")
- .append(MimeConstants.PAPERCLIP_EMOJI)
+ .append(MimeConstants.ATTACHMENT_MARKER)
.append(" ")
.append("")
.append(escapeHtml(safeMimeDecode(attachment.getFilename())))
@@ -1205,24 +1308,24 @@ public class EmlToPdf {
return;
}
- // 1. Find the screen position of all emoji anchors
- EmojiPositionFinder finder = new EmojiPositionFinder();
+ // 1. Find the screen position of all attachment markers
+ AttachmentMarkerPositionFinder finder = new AttachmentMarkerPositionFinder();
finder.setSortByPosition(true); // Process pages in order
finder.getText(document);
- List emojiPositions = finder.getPositions();
+ List markerPositions = finder.getPositions();
- // 2. Warn if the number of anchors and attachments don't match
- if (emojiPositions.size() != attachments.size()) {
+ // 2. Warn if the number of markers and attachments don't match
+ if (markerPositions.size() != attachments.size()) {
log.warn(
- "Found {} emoji anchors, but there are {} attachments. Annotation count may be incorrect.",
- emojiPositions.size(),
+ "Found {} attachment markers, but there are {} attachments. Annotation count may be incorrect.",
+ markerPositions.size(),
attachments.size());
}
- // 3. Create an invisible annotation over each found emoji
- int annotationsToAdd = Math.min(emojiPositions.size(), attachments.size());
+ // 3. Create an invisible annotation over each found marker
+ int annotationsToAdd = Math.min(markerPositions.size(), attachments.size());
for (int i = 0; i < annotationsToAdd; i++) {
- EmojiPosition position = emojiPositions.get(i);
+ MarkerPosition position = markerPositions.get(i);
EmailAttachment attachment = attachments.get(i);
if (attachment.getEmbeddedFilename() != null) {
@@ -1356,8 +1459,6 @@ public class EmlToPdf {
}
}
- // MIME header decoding functionality for RFC 2047 encoded headers - moved to constants
-
private static String decodeMimeHeader(String encodedText) {
if (encodedText == null || encodedText.trim().isEmpty()) {
return encodedText;
@@ -1446,13 +1547,73 @@ public class EmlToPdf {
}
try {
- return decodeMimeHeader(headerValue.trim());
+ if (isJakartaMailAvailable()) {
+ // Use Jakarta Mail's MimeUtility for proper MIME decoding
+ Class> mimeUtilityClass = Class.forName("jakarta.mail.internet.MimeUtility");
+ Method decodeText = mimeUtilityClass.getMethod("decodeText", String.class);
+ return (String) decodeText.invoke(null, headerValue.trim());
+ } else {
+ // Fallback to basic MIME decoding
+ return decodeMimeHeader(headerValue.trim());
+ }
} catch (Exception e) {
log.warn("Failed to decode MIME header, using original: {}", headerValue, e);
return headerValue;
}
}
+ private static boolean isValidJakartaMailPart(Object part) {
+ if (part == null) return false;
+
+ try {
+ // Check if the object implements jakarta.mail.Part interface
+ Class> partInterface = Class.forName("jakarta.mail.Part");
+ if (!partInterface.isInstance(part)) {
+ return false;
+ }
+
+ // Additional check for MimePart
+ try {
+ Class> mimePartInterface = Class.forName("jakarta.mail.internet.MimePart");
+ return mimePartInterface.isInstance(part);
+ } catch (ClassNotFoundException e) {
+ // MimePart not available, but Part is sufficient
+ return true;
+ }
+ } catch (ClassNotFoundException e) {
+ log.debug("Jakarta Mail Part interface not available for validation");
+ return false;
+ }
+ }
+
+ private static boolean isValidJakartaMailMultipart(Object multipart) {
+ if (multipart == null) return false;
+
+ try {
+ // Check if the object implements jakarta.mail.Multipart interface
+ Class> multipartInterface = Class.forName("jakarta.mail.Multipart");
+ if (!multipartInterface.isInstance(multipart)) {
+ return false;
+ }
+
+ // Additional check for MimeMultipart
+ try {
+ Class> mimeMultipartClass = Class.forName("jakarta.mail.internet.MimeMultipart");
+ if (mimeMultipartClass.isInstance(multipart)) {
+ log.debug("Found MimeMultipart instance for enhanced processing");
+ return true;
+ }
+ } catch (ClassNotFoundException e) {
+ log.debug("MimeMultipart not available, using base Multipart interface");
+ }
+
+ return true;
+ } catch (ClassNotFoundException e) {
+ log.debug("Jakarta Mail Multipart interface not available for validation");
+ return false;
+ }
+ }
+
@Data
public static class EmailContent {
private String subject;
@@ -1497,15 +1658,13 @@ public class EmlToPdf {
}
@Data
- public static class EmojiPosition {
+ public static class MarkerPosition {
private int pageIndex;
private float x;
private float y;
private String character;
- public EmojiPosition() {}
-
- public EmojiPosition(int pageIndex, float x, float y, String character) {
+ public MarkerPosition(int pageIndex, float x, float y, String character) {
this.pageIndex = pageIndex;
this.x = x;
this.y = y;
@@ -1513,14 +1672,15 @@ public class EmlToPdf {
}
}
- public static class EmojiPositionFinder extends org.apache.pdfbox.text.PDFTextStripper {
- @Getter private final List positions = new ArrayList<>();
+ public static class AttachmentMarkerPositionFinder
+ extends org.apache.pdfbox.text.PDFTextStripper {
+ @Getter private final List positions = new ArrayList<>();
private int currentPageIndex;
- private boolean sortByPosition;
+ protected boolean sortByPosition;
private boolean isInAttachmentSection;
private boolean attachmentSectionFound;
- public EmojiPositionFinder() throws IOException {
+ public AttachmentMarkerPositionFinder() {
super();
this.currentPageIndex = 0;
this.sortByPosition = false;
@@ -1563,24 +1723,18 @@ public class EmlToPdf {
isInAttachmentSection = false;
}
- // Only look for emojis if we are in the attachment section
+ // Only look for markers if we are in the attachment section
if (isInAttachmentSection) {
- // Look for paperclip emoji characters (U+1F4CE)
- String paperclipEmoji = "\uD83D\uDCCE"; // 📎 Unicode representation
-
- for (int i = 0; i < string.length(); i++) {
- // Check if we have a complete paperclip emoji at this position
- if (i < string.length() - 1
- && string.substring(i, i + 2).equals(paperclipEmoji)
- && i < textPositions.size()) {
-
+ String attachmentMarker = MimeConstants.ATTACHMENT_MARKER;
+ for (int i = 0; (i = string.indexOf(attachmentMarker, i)) != -1; i++) {
+ if (i < textPositions.size()) {
org.apache.pdfbox.text.TextPosition textPosition = textPositions.get(i);
- EmojiPosition position =
- new EmojiPosition(
+ MarkerPosition position =
+ new MarkerPosition(
currentPageIndex,
textPosition.getXDirAdj(),
textPosition.getYDirAdj(),
- paperclipEmoji);
+ attachmentMarker);
positions.add(position);
}
}
@@ -1592,16 +1746,5 @@ public class EmlToPdf {
public void setSortByPosition(boolean sortByPosition) {
this.sortByPosition = sortByPosition;
}
-
- public boolean isSortByPosition() {
- return sortByPosition;
- }
-
- public void reset() {
- positions.clear();
- currentPageIndex = 0;
- isInAttachmentSection = false;
- attachmentSectionFound = false;
- }
}
}
diff --git a/stirling-pdf/src/main/java/stirling/software/SPDF/config/EndpointConfiguration.java b/stirling-pdf/src/main/java/stirling/software/SPDF/config/EndpointConfiguration.java
index c9872992a..2e7a197de 100644
--- a/stirling-pdf/src/main/java/stirling/software/SPDF/config/EndpointConfiguration.java
+++ b/stirling-pdf/src/main/java/stirling/software/SPDF/config/EndpointConfiguration.java
@@ -10,7 +10,6 @@ import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import lombok.extern.slf4j.Slf4j;
-
import stirling.software.common.model.ApplicationProperties;
@Service
@@ -142,6 +141,7 @@ public class EndpointConfiguration {
addEndpointToGroup("Convert", "markdown-to-pdf");
addEndpointToGroup("Convert", "pdf-to-csv");
addEndpointToGroup("Convert", "pdf-to-markdown");
+ addEndpointToGroup("Convert", "eml-to-pdf");
// Adding endpoints to "Security" group
addEndpointToGroup("Security", "add-password");
@@ -265,6 +265,7 @@ public class EndpointConfiguration {
addEndpointToGroup("Weasyprint", "html-to-pdf");
addEndpointToGroup("Weasyprint", "url-to-pdf");
addEndpointToGroup("Weasyprint", "markdown-to-pdf");
+ addEndpointToGroup("Weasyprint", "eml-to-pdf");
// Pdftohtml dependent endpoints
addEndpointToGroup("Pdftohtml", "pdf-to-html");