Browse Source

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
pull/33297/head
Simon Baslé 2 years ago
parent
commit
f1a99cd968
  1. 100
      spring-context-support/src/main/java/org/springframework/mail/javamail/MimeMessageHelper.java

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

@ -905,12 +905,47 @@ public class MimeMessageHelper { @@ -905,12 +905,47 @@ public class MimeMessageHelper {
* @see #addInline(String, org.springframework.core.io.Resource)
*/
public void addInline(String contentId, DataSource dataSource) throws MessagingException {
addInline(contentId, null, dataSource);
}
/**
* Add an inline element to the MimeMessage, taking the content from a
* {@code jakarta.activation.DataSource} and assigning the provided
* {@code inlineFileName} to the element.
* <p>Note that the InputStream returned by the DataSource implementation
* needs to be a <i>fresh one on each call</i>, as JavaMail will invoke
* {@code getInputStream()} multiple times.
* <p><b>NOTE:</b> Invoke {@code addInline} <i>after</i> {@link #setText};
* else, mail readers might not be able to resolve inline references correctly.
* @param contentId the content ID to use. Will end up as "Content-ID" header
* in the body part, surrounded by angle brackets: e.g. "myId" &rarr; "&lt;myId&gt;".
* Can be referenced in HTML source via src="cid:myId" expressions.
* @param inlineFilename the fileName to use for the inline element's part
* @param dataSource the {@code jakarta.activation.DataSource} to take
* the content from, determining the InputStream and the content type
* @throws MessagingException in case of errors
* @since 6.2
* @see #addInline(String, java.io.File)
* @see #addInline(String, org.springframework.core.io.Resource)
*/
public void addInline(String contentId, @Nullable String inlineFilename, DataSource dataSource)
throws MessagingException {
Assert.notNull(contentId, "Content ID must not be null");
Assert.notNull(dataSource, "DataSource must not be null");
MimeBodyPart mimeBodyPart = new MimeBodyPart();
mimeBodyPart.setDisposition(Part.INLINE);
mimeBodyPart.setContentID("<" + contentId + ">");
mimeBodyPart.setDataHandler(new DataHandler(dataSource));
if (inlineFilename != null) {
try {
mimeBodyPart.setFileName(isEncodeFilenames() ?
MimeUtility.encodeText(inlineFilename) : inlineFilename);
}
catch (UnsupportedEncodingException ex) {
throw new MessagingException("Failed to encode inline filename", ex);
}
}
getMimeMultipart().addBodyPart(mimeBodyPart);
}
@ -989,14 +1024,75 @@ public class MimeMessageHelper { @@ -989,14 +1024,75 @@ public class MimeMessageHelper {
public void addInline(String contentId, InputStreamSource inputStreamSource, String contentType)
throws MessagingException {
addInline(contentId, "inline", inputStreamSource, contentType);
}
/**
* Add an inline element to the MimeMessage, taking the content from an
* {@code org.springframework.core.InputStreamResource}, and
* specifying the inline fileName explicitly.
* <p>The content type will be determined by the name of the given
* content file. Do not use this for temporary files with arbitrary
* filenames (possibly ending in ".tmp" or the like)!
* <p>Note that the InputStream returned by the InputStreamSource implementation
* needs to be a <i>fresh one on each call</i>, as JavaMail will invoke
* {@code getInputStream()} multiple times.
* <p><b>NOTE:</b> Invoke {@code addInline} <i>after</i> {@code setText};
* else, mail readers might not be able to resolve inline references correctly.
* @param contentId the content ID to use. Will end up as "Content-ID" header
* in the body part, surrounded by angle brackets: e.g. "myId" &rarr; "&lt;myId&gt;".
* Can be referenced in HTML source via src="cid:myId" expressions.
* @param inlineFilename the file name to use for the inline element
* @param inputStreamSource the resource to take the content from
* @throws MessagingException in case of errors
* @since 6.2
* @see #setText(String)
* @see #getFileTypeMap
* @see #addInline(String, org.springframework.core.io.Resource)
* @see #addInline(String, String, jakarta.activation.DataSource)
*/
public void addInline(String contentId, String inlineFilename, InputStreamSource inputStreamSource)
throws MessagingException {
String contentType = getFileTypeMap().getContentType(inlineFilename);
addInline(contentId, inlineFilename, inputStreamSource, contentType);
}
/**
* Add an inline element to the MimeMessage, taking the content from an
* {@code org.springframework.core.InputStreamResource}, and
* specifying the inline fileName and content type explicitly.
* <p>You can determine the content type for any given filename via a Java
* Activation Framework's FileTypeMap, for example the one held by this helper.
* <p>Note that the InputStream returned by the InputStreamSource implementation
* needs to be a <i>fresh one on each call</i>, as JavaMail will invoke
* {@code getInputStream()} multiple times.
* <p><b>NOTE:</b> Invoke {@code addInline} <i>after</i> {@code setText};
* else, mail readers might not be able to resolve inline references correctly.
* @param contentId the content ID to use. Will end up as "Content-ID" header
* in the body part, surrounded by angle brackets: e.g. "myId" &rarr; "&lt;myId&gt;".
* Can be referenced in HTML source via src="cid:myId" expressions.
* @param inlineFilename the fileName to use for the inline element's part
* @param inputStreamSource the resource to take the content from
* @param contentType the content type to use for the element
* @throws MessagingException in case of errors
* @since 6.2
* @see #setText
* @see #getFileTypeMap
* @see #addInline(String, org.springframework.core.io.Resource)
* @see #addInline(String, String, jakarta.activation.DataSource)
*/
public void addInline(String contentId, String inlineFilename, InputStreamSource inputStreamSource, String contentType)
throws MessagingException {
Assert.notNull(inputStreamSource, "InputStreamSource must not be null");
if (inputStreamSource instanceof Resource resource && resource.isOpen()) {
throw new IllegalArgumentException(
"Passed-in Resource contains an open stream: invalid argument. " +
"JavaMail requires an InputStreamSource that creates a fresh stream for every call.");
}
DataSource dataSource = createDataSource(inputStreamSource, contentType, "inline");
addInline(contentId, dataSource);
DataSource dataSource = createDataSource(inputStreamSource, contentType, inlineFilename);
addInline(contentId, inlineFilename, dataSource);
}
/**

Loading…
Cancel
Save