Skip to content

Commit f1a99cd

Browse files
committed
Allow setting filename for inline elements in MimeMessageHelper
This change adds several overloads of `MimeMessageHelper#addInline` which allow users to specify a file name for inline elements added from an `InputStreamResource` or a `jakarta.activation.DataSource`. Closes gh-33230
1 parent c71f98a commit f1a99cd

File tree

1 file changed

+98
-2
lines changed

1 file changed

+98
-2
lines changed

spring-context-support/src/main/java/org/springframework/mail/javamail/MimeMessageHelper.java

+98-2
Original file line numberDiff line numberDiff line change
@@ -905,12 +905,47 @@ private void setHtmlTextToMimePart(MimePart mimePart, String text) throws Messag
905905
* @see #addInline(String, org.springframework.core.io.Resource)
906906
*/
907907
public void addInline(String contentId, DataSource dataSource) throws MessagingException {
908+
addInline(contentId, null, dataSource);
909+
}
910+
911+
/**
912+
* Add an inline element to the MimeMessage, taking the content from a
913+
* {@code jakarta.activation.DataSource} and assigning the provided
914+
* {@code inlineFileName} to the element.
915+
* <p>Note that the InputStream returned by the DataSource implementation
916+
* needs to be a <i>fresh one on each call</i>, as JavaMail will invoke
917+
* {@code getInputStream()} multiple times.
918+
* <p><b>NOTE:</b> Invoke {@code addInline} <i>after</i> {@link #setText};
919+
* else, mail readers might not be able to resolve inline references correctly.
920+
* @param contentId the content ID to use. Will end up as "Content-ID" header
921+
* in the body part, surrounded by angle brackets: e.g. "myId" &rarr; "&lt;myId&gt;".
922+
* Can be referenced in HTML source via src="cid:myId" expressions.
923+
* @param inlineFilename the fileName to use for the inline element's part
924+
* @param dataSource the {@code jakarta.activation.DataSource} to take
925+
* the content from, determining the InputStream and the content type
926+
* @throws MessagingException in case of errors
927+
* @since 6.2
928+
* @see #addInline(String, java.io.File)
929+
* @see #addInline(String, org.springframework.core.io.Resource)
930+
*/
931+
public void addInline(String contentId, @Nullable String inlineFilename, DataSource dataSource)
932+
throws MessagingException {
933+
908934
Assert.notNull(contentId, "Content ID must not be null");
909935
Assert.notNull(dataSource, "DataSource must not be null");
910936
MimeBodyPart mimeBodyPart = new MimeBodyPart();
911937
mimeBodyPart.setDisposition(Part.INLINE);
912938
mimeBodyPart.setContentID("<" + contentId + ">");
913939
mimeBodyPart.setDataHandler(new DataHandler(dataSource));
940+
if (inlineFilename != null) {
941+
try {
942+
mimeBodyPart.setFileName(isEncodeFilenames() ?
943+
MimeUtility.encodeText(inlineFilename) : inlineFilename);
944+
}
945+
catch (UnsupportedEncodingException ex) {
946+
throw new MessagingException("Failed to encode inline filename", ex);
947+
}
948+
}
914949
getMimeMultipart().addBodyPart(mimeBodyPart);
915950
}
916951

@@ -989,14 +1024,75 @@ public void addInline(String contentId, Resource resource) throws MessagingExcep
9891024
public void addInline(String contentId, InputStreamSource inputStreamSource, String contentType)
9901025
throws MessagingException {
9911026

1027+
addInline(contentId, "inline", inputStreamSource, contentType);
1028+
}
1029+
1030+
/**
1031+
* Add an inline element to the MimeMessage, taking the content from an
1032+
* {@code org.springframework.core.InputStreamResource}, and
1033+
* specifying the inline fileName explicitly.
1034+
* <p>The content type will be determined by the name of the given
1035+
* content file. Do not use this for temporary files with arbitrary
1036+
* filenames (possibly ending in ".tmp" or the like)!
1037+
* <p>Note that the InputStream returned by the InputStreamSource implementation
1038+
* needs to be a <i>fresh one on each call</i>, as JavaMail will invoke
1039+
* {@code getInputStream()} multiple times.
1040+
* <p><b>NOTE:</b> Invoke {@code addInline} <i>after</i> {@code setText};
1041+
* else, mail readers might not be able to resolve inline references correctly.
1042+
* @param contentId the content ID to use. Will end up as "Content-ID" header
1043+
* in the body part, surrounded by angle brackets: e.g. "myId" &rarr; "&lt;myId&gt;".
1044+
* Can be referenced in HTML source via src="cid:myId" expressions.
1045+
* @param inlineFilename the file name to use for the inline element
1046+
* @param inputStreamSource the resource to take the content from
1047+
* @throws MessagingException in case of errors
1048+
* @since 6.2
1049+
* @see #setText(String)
1050+
* @see #getFileTypeMap
1051+
* @see #addInline(String, org.springframework.core.io.Resource)
1052+
* @see #addInline(String, String, jakarta.activation.DataSource)
1053+
*/
1054+
public void addInline(String contentId, String inlineFilename, InputStreamSource inputStreamSource)
1055+
throws MessagingException {
1056+
1057+
String contentType = getFileTypeMap().getContentType(inlineFilename);
1058+
addInline(contentId, inlineFilename, inputStreamSource, contentType);
1059+
}
1060+
1061+
/**
1062+
* Add an inline element to the MimeMessage, taking the content from an
1063+
* {@code org.springframework.core.InputStreamResource}, and
1064+
* specifying the inline fileName and content type explicitly.
1065+
* <p>You can determine the content type for any given filename via a Java
1066+
* Activation Framework's FileTypeMap, for example the one held by this helper.
1067+
* <p>Note that the InputStream returned by the InputStreamSource implementation
1068+
* needs to be a <i>fresh one on each call</i>, as JavaMail will invoke
1069+
* {@code getInputStream()} multiple times.
1070+
* <p><b>NOTE:</b> Invoke {@code addInline} <i>after</i> {@code setText};
1071+
* else, mail readers might not be able to resolve inline references correctly.
1072+
* @param contentId the content ID to use. Will end up as "Content-ID" header
1073+
* in the body part, surrounded by angle brackets: e.g. "myId" &rarr; "&lt;myId&gt;".
1074+
* Can be referenced in HTML source via src="cid:myId" expressions.
1075+
* @param inlineFilename the fileName to use for the inline element's part
1076+
* @param inputStreamSource the resource to take the content from
1077+
* @param contentType the content type to use for the element
1078+
* @throws MessagingException in case of errors
1079+
* @since 6.2
1080+
* @see #setText
1081+
* @see #getFileTypeMap
1082+
* @see #addInline(String, org.springframework.core.io.Resource)
1083+
* @see #addInline(String, String, jakarta.activation.DataSource)
1084+
*/
1085+
public void addInline(String contentId, String inlineFilename, InputStreamSource inputStreamSource, String contentType)
1086+
throws MessagingException {
1087+
9921088
Assert.notNull(inputStreamSource, "InputStreamSource must not be null");
9931089
if (inputStreamSource instanceof Resource resource && resource.isOpen()) {
9941090
throw new IllegalArgumentException(
9951091
"Passed-in Resource contains an open stream: invalid argument. " +
9961092
"JavaMail requires an InputStreamSource that creates a fresh stream for every call.");
9971093
}
998-
DataSource dataSource = createDataSource(inputStreamSource, contentType, "inline");
999-
addInline(contentId, dataSource);
1094+
DataSource dataSource = createDataSource(inputStreamSource, contentType, inlineFilename);
1095+
addInline(contentId, inlineFilename, dataSource);
10001096
}
10011097

10021098
/**

0 commit comments

Comments
 (0)