diff --git a/src/main/java/org/simplejavamail/email/AttachmentResource.java b/src/main/java/org/simplejavamail/email/AttachmentResource.java
index a414aa8e1..607e7af12 100644
--- a/src/main/java/org/simplejavamail/email/AttachmentResource.java
+++ b/src/main/java/org/simplejavamail/email/AttachmentResource.java
@@ -3,8 +3,8 @@
import javax.activation.DataSource;
/**
- * A named immutable email attachment information object. The name can be a simple name, a filename or a named embedded image (eg. <cid:footer>). Contains
- * a {@link DataSource} that is compatible with the javax.mail API.
+ * A named immutable email attachment information object. The name can be a simple name, a filename or a named embedded image (eg.
+ * <cid:footer>). Contains a {@link DataSource} that is compatible with the javax.mail API.
*
* @author Benny Bottema
* @see DataSource
@@ -24,8 +24,9 @@ public class AttachmentResource {
/**
* Constructor; initializes the attachment resource with a name and data.
*
- * @param name The name of the attachment which can be a simple name, a filename or a named embedded image (eg. <cid:footer>)
- * @param dataSource The attachment data.
+ * @param name The name of the attachment which can be a simple name, a filename or a named embedded image (eg. <cid:footer>). Leave
+ * null
to fall back on {@link DataSource#getName()}.
+ * @param dataSource The attachment data. If no name was provided, the name of this datasource is used if provided.
* @see DataSource
*/
public AttachmentResource(final String name, final DataSource dataSource) {
diff --git a/src/main/java/org/simplejavamail/internal/util/MimeMessageParser.java b/src/main/java/org/simplejavamail/internal/util/MimeMessageParser.java
index 9b2f82cc6..9f1b052ea 100644
--- a/src/main/java/org/simplejavamail/internal/util/MimeMessageParser.java
+++ b/src/main/java/org/simplejavamail/internal/util/MimeMessageParser.java
@@ -25,6 +25,8 @@
import java.io.*;
import java.util.*;
+import static org.simplejavamail.internal.util.MiscUtil.valueNullOrEmpty;
+
/**
* heavily modified version based on org.apache.commons.mail.util.MimeMessageParser.html
* Parses a MimeMessage and stores the individual parts such a plain text,
@@ -34,344 +36,365 @@
*/
public class MimeMessageParser {
- private static final List DEFAULT_HEADERS = new ArrayList<>();
+ private static final List DEFAULT_HEADERS = new ArrayList<>();
- static {
- // taken from: protected javax.mail.internet.InternetHeaders constructor
- /*
- * When extracting information to create an Email, we're not interested in the following headers:
+ static {
+ // taken from: protected javax.mail.internet.InternetHeaders constructor
+ /*
+ * When extracting information to create an Email, we're not interested in the following headers:
*/
- DEFAULT_HEADERS.add("Return-Path");
- DEFAULT_HEADERS.add("Received");
- DEFAULT_HEADERS.add("Resent-Date");
- DEFAULT_HEADERS.add("Resent-From");
- DEFAULT_HEADERS.add("Resent-Sender");
- DEFAULT_HEADERS.add("Resent-To");
- DEFAULT_HEADERS.add("Resent-Cc");
- DEFAULT_HEADERS.add("Resent-Bcc");
- DEFAULT_HEADERS.add("Resent-Message-Id");
- DEFAULT_HEADERS.add("Date");
- DEFAULT_HEADERS.add("From");
- DEFAULT_HEADERS.add("Sender");
- DEFAULT_HEADERS.add("Reply-To");
- DEFAULT_HEADERS.add("To");
- DEFAULT_HEADERS.add("Cc");
- DEFAULT_HEADERS.add("Bcc");
- DEFAULT_HEADERS.add("Message-Id");
- DEFAULT_HEADERS.add("In-Reply-To");
- DEFAULT_HEADERS.add("References");
- DEFAULT_HEADERS.add("Subject");
- DEFAULT_HEADERS.add("Comments");
- DEFAULT_HEADERS.add("Keywords");
- DEFAULT_HEADERS.add("Errors-To");
- DEFAULT_HEADERS.add("MIME-Version");
- DEFAULT_HEADERS.add("Content-Type");
- DEFAULT_HEADERS.add("Content-Transfer-Encoding");
- DEFAULT_HEADERS.add("Content-MD5");
- DEFAULT_HEADERS.add(":");
- DEFAULT_HEADERS.add("Content-Length");
- DEFAULT_HEADERS.add("Status");
- // extra headers that should be ignored, which may originate from nested attachments
- DEFAULT_HEADERS.add("Content-Disposition");
- DEFAULT_HEADERS.add("size");
- DEFAULT_HEADERS.add("filename");
- DEFAULT_HEADERS.add("Content-ID");
- DEFAULT_HEADERS.add("name");
- DEFAULT_HEADERS.add("From");
- }
-
- private final Map attachmentList = new HashMap<>();
-
- private final Map cidMap = new HashMap<>();
-
- private final Map headers = new HashMap<>();
-
- private final MimeMessage mimeMessage;
-
- private String plainContent;
-
- private String htmlContent;
-
- /**
- * Constructs an instance with the MimeMessage to be extracted.
- *
- * @param message the message to parse
- */
- public MimeMessageParser(final MimeMessage message) {
- this.mimeMessage = message;
- }
-
- /**
- * Does the actual extraction.
- *
- * @return this instance
- */
- public MimeMessageParser parse() throws MessagingException, IOException {
- this.parse(mimeMessage);
- return this;
- }
-
- /**
- * @return the 'to' recipients of the message
- */
- public List getTo() throws MessagingException {
- return getInternetAddresses(this.mimeMessage.getRecipients(Message.RecipientType.TO));
- }
-
- /**
- * @return the 'cc' recipients of the message
- */
- public List getCc() throws MessagingException {
- return getInternetAddresses(this.mimeMessage.getRecipients(Message.RecipientType.CC));
- }
-
- /**
- * @return the 'bcc' recipients of the message
- */
- public List getBcc() throws MessagingException {
- return getInternetAddresses(this.mimeMessage.getRecipients(Message.RecipientType.BCC));
- }
-
- private static List getInternetAddresses(final Address[] recipients) {
- final List addresses = (recipients != null) ? Arrays.asList(recipients) : new ArrayList();
- final List mailAddresses = new ArrayList<>();
- for (final Address address : addresses) {
- if (address instanceof InternetAddress) {
- mailAddresses.add((InternetAddress) address);
- }
- }
- return mailAddresses;
- }
-
- /**
- * @return the 'from' field of the message
- */
- public InternetAddress getFrom() throws MessagingException {
- final Address[] addresses = this.mimeMessage.getFrom();
- if (addresses == null || addresses.length == 0) {
- return null;
- }
- return (InternetAddress) addresses[0];
- }
-
- /**
- * @return the 'replyTo' address of the email
- */
- public InternetAddress getReplyTo() throws MessagingException {
- final Address[] addresses = this.mimeMessage.getReplyTo();
- if (addresses == null || addresses.length == 0) {
- return null;
- }
- return (InternetAddress) addresses[0];
- }
-
- /**
- * @return the mail subject
- */
- public String getSubject() throws MessagingException {
- return this.mimeMessage.getSubject();
- }
-
- /**
- * Extracts the content of a MimeMessage recursively.
- *
- * @param part the current MimePart
- * @throws MessagingException parsing the MimeMessage failed
- * @throws IOException parsing the MimeMessage failed
- */
- private void parse(final MimePart part)
- throws MessagingException, IOException {
- extractCustomUserHeaders(part);
-
- if (isMimeType(part, "text/plain") && plainContent == null
- && !Part.ATTACHMENT.equalsIgnoreCase(part.getDisposition())) {
- plainContent = (String) part.getContent();
- } else {
- if (isMimeType(part, "text/html") && htmlContent == null
- && !Part.ATTACHMENT.equalsIgnoreCase(part.getDisposition())) {
- htmlContent = (String) part.getContent();
- } else {
- if (isMimeType(part, "multipart/*")) {
- final Multipart mp = (Multipart) part.getContent();
- final int count = mp.getCount();
-
- // iterate over all MimeBodyPart
- for (int i = 0; i < count; i++) {
- parse((MimeBodyPart) mp.getBodyPart(i));
- }
- } else {
- final DataSource ds = createDataSource(part);
- // If the diposition is not provided, the part should be treat as attachment
- if (part.getDisposition() == null || Part.ATTACHMENT.equalsIgnoreCase(part.getDisposition())) {
- this.attachmentList.put(part.getContentID(), ds);
- } else if (Part.INLINE.equalsIgnoreCase(part.getDisposition())) {
- this.cidMap.put(part.getContentID(), ds);
- } else {
- throw new IllegalStateException("invalid attachment type");
- }
- }
- }
- }
- }
-
- private void extractCustomUserHeaders(final MimePart part) throws MessagingException {
- final Enumeration e = part.getAllHeaders();
- while (e.hasMoreElements()) {
- final Object headerObj = e.nextElement();
- if (headerObj instanceof Header) {
- final Header header = (Header) headerObj;
- if (isCustomUserHeader(header)) {
- headers.put(header.getName(), header.getValue());
- }
- }
- }
- }
-
- private static boolean isCustomUserHeader(final Header header) {
- return !DEFAULT_HEADERS.contains(header.getName());
- }
-
- /**
- * Checks whether the MimePart contains an object of the given mime type.
- *
- * @param part the current MimePart
- * @param mimeType the mime type to check
- * @return {@code true} if the MimePart matches the given mime type, {@code false} otherwise
- * @throws MessagingException parsing the MimeMessage failed
- */
- private static boolean isMimeType(final MimePart part, final String mimeType)
- throws MessagingException {
- // Do not use part.isMimeType(String) as it is broken for MimeBodyPart
- // and does not really check the actual content type.
-
- try {
- final ContentType ct = new ContentType(part.getDataHandler().getContentType());
- return ct.match(mimeType);
- } catch (final ParseException ex) {
- return part.getContentType().equalsIgnoreCase(mimeType);
- }
- }
-
- /**
- * Parses the MimePart to create a DataSource.
- *
- * @param part the current part to be processed
- * @return the DataSource
- * @throws MessagingException creating the DataSource failed
- * @throws IOException creating the DataSource failed
- */
- private static DataSource createDataSource(final MimePart part)
- throws MessagingException, IOException {
- final DataHandler dataHandler = part.getDataHandler();
- final DataSource dataSource = dataHandler.getDataSource();
- final String contentType = getBaseMimeType(dataSource.getContentType());
- final byte[] content = MimeMessageParser.getContent(dataSource.getInputStream());
- final ByteArrayDataSource result = new ByteArrayDataSource(content, contentType);
- final String dataSourceName = getDataSourceName(part, dataSource);
-
- result.setName(dataSourceName);
- return result;
- }
-
- /**
- * Determines the name of the data source if it is not already set.
- *
- * @param part the mail part
- * @param dataSource the data source
- * @return the name of the data source or {@code null} if no name can be determined
- * @throws MessagingException accessing the part failed
- * @throws UnsupportedEncodingException decoding the text failed
- */
- private static String getDataSourceName(final Part part, final DataSource dataSource)
- throws MessagingException, UnsupportedEncodingException {
- String result = dataSource.getName();
-
- if (result == null || result.length() == 0) {
- result = part.getFileName();
- }
-
- if (result != null && result.length() > 0) {
- result = MimeUtility.decodeText(result);
- } else {
- result = null;
- }
-
- return result;
- }
-
- /**
- * Read the content of the input stream.
- *
- * @param is the input stream to process
- * @return the content of the input stream
- * @throws IOException reading the input stream failed
- */
- private static byte[] getContent(final InputStream is)
- throws IOException {
- int ch;
- final byte[] result;
-
- final ByteArrayOutputStream os = new ByteArrayOutputStream();
- final BufferedInputStream isReader = new BufferedInputStream(is);
- final BufferedOutputStream osWriter = new BufferedOutputStream(os);
-
- while ((ch = isReader.read()) != -1) {
- osWriter.write(ch);
- }
-
- osWriter.flush();
- result = os.toByteArray();
- osWriter.close();
-
- return result;
- }
-
- /**
- * Parses the mimeType.
- *
- * @param fullMimeType the mime type from the mail api
- * @return the real mime type
- */
- private static String getBaseMimeType(final String fullMimeType) {
- final int pos = fullMimeType.indexOf(';');
- if (pos >= 0) {
- return fullMimeType.substring(0, pos);
- }
- return fullMimeType;
- }
-
- /**
- * @return {@link #cidMap}
- */
- public Map getCidMap() {
- return cidMap;
- }
-
- /**
- * @return {@link #headers}
- */
- public Map getHeaders() {
- return headers;
- }
-
- /**
- * @return {@link #plainContent}
- */
- public String getPlainContent() {
- return plainContent;
- }
-
- /**
- * @return {@link #attachmentList}
- */
- public Map getAttachmentList() {
- return attachmentList;
- }
-
- /**
- * @return {@link #htmlContent}
- */
- public String getHtmlContent() {
- return htmlContent;
- }
+ DEFAULT_HEADERS.add("Return-Path");
+ DEFAULT_HEADERS.add("Received");
+ DEFAULT_HEADERS.add("Resent-Date");
+ DEFAULT_HEADERS.add("Resent-From");
+ DEFAULT_HEADERS.add("Resent-Sender");
+ DEFAULT_HEADERS.add("Resent-To");
+ DEFAULT_HEADERS.add("Resent-Cc");
+ DEFAULT_HEADERS.add("Resent-Bcc");
+ DEFAULT_HEADERS.add("Resent-Message-Id");
+ DEFAULT_HEADERS.add("Date");
+ DEFAULT_HEADERS.add("From");
+ DEFAULT_HEADERS.add("Sender");
+ DEFAULT_HEADERS.add("Reply-To");
+ DEFAULT_HEADERS.add("To");
+ DEFAULT_HEADERS.add("Cc");
+ DEFAULT_HEADERS.add("Bcc");
+ DEFAULT_HEADERS.add("Message-Id");
+ DEFAULT_HEADERS.add("In-Reply-To");
+ DEFAULT_HEADERS.add("References");
+ DEFAULT_HEADERS.add("Subject");
+ DEFAULT_HEADERS.add("Comments");
+ DEFAULT_HEADERS.add("Keywords");
+ DEFAULT_HEADERS.add("Errors-To");
+ DEFAULT_HEADERS.add("MIME-Version");
+ DEFAULT_HEADERS.add("Content-Type");
+ DEFAULT_HEADERS.add("Content-Transfer-Encoding");
+ DEFAULT_HEADERS.add("Content-MD5");
+ DEFAULT_HEADERS.add(":");
+ DEFAULT_HEADERS.add("Content-Length");
+ DEFAULT_HEADERS.add("Status");
+ // extra headers that should be ignored, which may originate from nested attachments
+ DEFAULT_HEADERS.add("Content-Disposition");
+ DEFAULT_HEADERS.add("size");
+ DEFAULT_HEADERS.add("filename");
+ DEFAULT_HEADERS.add("Content-ID");
+ DEFAULT_HEADERS.add("name");
+ DEFAULT_HEADERS.add("From");
+ }
+
+ private final Map attachmentList = new HashMap<>();
+
+ private final Map cidMap = new HashMap<>();
+
+ private final Map headers = new HashMap<>();
+
+ private final MimeMessage mimeMessage;
+
+ private String plainContent;
+
+ private String htmlContent;
+
+ /**
+ * Constructs an instance with the MimeMessage to be extracted.
+ *
+ * @param message the message to parse
+ */
+ public MimeMessageParser(final MimeMessage message) {
+ this.mimeMessage = message;
+ }
+
+ /**
+ * Does the actual extraction.
+ *
+ * @return this instance
+ */
+ public MimeMessageParser parse()
+ throws MessagingException, IOException {
+ this.parse(mimeMessage);
+ return this;
+ }
+
+ /**
+ * @return the 'to' recipients of the message
+ */
+ public List getTo()
+ throws MessagingException {
+ return getInternetAddresses(this.mimeMessage.getRecipients(Message.RecipientType.TO));
+ }
+
+ /**
+ * @return the 'cc' recipients of the message
+ */
+ public List getCc()
+ throws MessagingException {
+ return getInternetAddresses(this.mimeMessage.getRecipients(Message.RecipientType.CC));
+ }
+
+ /**
+ * @return the 'bcc' recipients of the message
+ */
+ public List getBcc()
+ throws MessagingException {
+ return getInternetAddresses(this.mimeMessage.getRecipients(Message.RecipientType.BCC));
+ }
+
+ private static List getInternetAddresses(final Address[] recipients) {
+ final List addresses = (recipients != null) ? Arrays.asList(recipients) : new ArrayList();
+ final List mailAddresses = new ArrayList<>();
+ for (final Address address : addresses) {
+ if (address instanceof InternetAddress) {
+ mailAddresses.add((InternetAddress) address);
+ }
+ }
+ return mailAddresses;
+ }
+
+ /**
+ * @return the 'from' field of the message
+ */
+ public InternetAddress getFrom()
+ throws MessagingException {
+ final Address[] addresses = this.mimeMessage.getFrom();
+ if (addresses == null || addresses.length == 0) {
+ return null;
+ }
+ return (InternetAddress) addresses[0];
+ }
+
+ /**
+ * @return the 'replyTo' address of the email
+ */
+ public InternetAddress getReplyTo()
+ throws MessagingException {
+ final Address[] addresses = this.mimeMessage.getReplyTo();
+ if (addresses == null || addresses.length == 0) {
+ return null;
+ }
+ return (InternetAddress) addresses[0];
+ }
+
+ /**
+ * @return the mail subject
+ */
+ public String getSubject()
+ throws MessagingException {
+ return this.mimeMessage.getSubject();
+ }
+
+ /**
+ * Extracts the content of a MimeMessage recursively.
+ *
+ * @param part the current MimePart
+ * @throws MessagingException parsing the MimeMessage failed
+ * @throws IOException parsing the MimeMessage failed
+ */
+ private void parse(final MimePart part)
+ throws MessagingException, IOException {
+ extractCustomUserHeaders(part);
+
+ if (isMimeType(part, "text/plain") && plainContent == null
+ && !Part.ATTACHMENT.equalsIgnoreCase(part.getDisposition())) {
+ plainContent = (String) part.getContent();
+ } else {
+ if (isMimeType(part, "text/html") && htmlContent == null
+ && !Part.ATTACHMENT.equalsIgnoreCase(part.getDisposition())) {
+ htmlContent = (String) part.getContent();
+ } else {
+ if (isMimeType(part, "multipart/*")) {
+ final Multipart mp = (Multipart) part.getContent();
+ final int count = mp.getCount();
+
+ // iterate over all MimeBodyPart
+ for (int i = 0; i < count; i++) {
+ parse((MimeBodyPart) mp.getBodyPart(i));
+ }
+ } else {
+ final DataSource ds = createDataSource(part);
+ // If the diposition is not provided, the part should be treat as attachment
+ if (part.getDisposition() == null || Part.ATTACHMENT.equalsIgnoreCase(part.getDisposition())) {
+ this.attachmentList.put(parseResourceName(part.getContentID(), part.getFileName()), ds);
+ } else if (Part.INLINE.equalsIgnoreCase(part.getDisposition())) {
+ this.cidMap.put(part.getContentID(), ds);
+ } else {
+ throw new IllegalStateException("invalid attachment type");
+ }
+ }
+ }
+ }
+ }
+
+ private String parseResourceName(String contentID, String fileName) {
+ String extension = "";
+ if (!valueNullOrEmpty(fileName) && fileName.contains(".")) {
+ extension = fileName.substring(fileName.lastIndexOf("."), fileName.length());
+ }
+ if (!valueNullOrEmpty(contentID)) {
+ return (contentID.endsWith(extension)) ? contentID : contentID + extension;
+ } else {
+ return fileName;
+ }
+ }
+
+ private void extractCustomUserHeaders(final MimePart part)
+ throws MessagingException {
+ final Enumeration e = part.getAllHeaders();
+ while (e.hasMoreElements()) {
+ final Object headerObj = e.nextElement();
+ if (headerObj instanceof Header) {
+ final Header header = (Header) headerObj;
+ if (isCustomUserHeader(header)) {
+ headers.put(header.getName(), header.getValue());
+ }
+ }
+ }
+ }
+
+ private static boolean isCustomUserHeader(final Header header) {
+ return !DEFAULT_HEADERS.contains(header.getName());
+ }
+
+ /**
+ * Checks whether the MimePart contains an object of the given mime type.
+ *
+ * @param part the current MimePart
+ * @param mimeType the mime type to check
+ * @return {@code true} if the MimePart matches the given mime type, {@code false} otherwise
+ * @throws MessagingException parsing the MimeMessage failed
+ */
+ private static boolean isMimeType(final MimePart part, final String mimeType)
+ throws MessagingException {
+ // Do not use part.isMimeType(String) as it is broken for MimeBodyPart
+ // and does not really check the actual content type.
+
+ try {
+ final ContentType ct = new ContentType(part.getDataHandler().getContentType());
+ return ct.match(mimeType);
+ } catch (final ParseException ex) {
+ return part.getContentType().equalsIgnoreCase(mimeType);
+ }
+ }
+
+ /**
+ * Parses the MimePart to create a DataSource.
+ *
+ * @param part the current part to be processed
+ * @return the DataSource
+ * @throws MessagingException creating the DataSource failed
+ * @throws IOException creating the DataSource failed
+ */
+ private static DataSource createDataSource(final MimePart part)
+ throws MessagingException, IOException {
+ final DataHandler dataHandler = part.getDataHandler();
+ final DataSource dataSource = dataHandler.getDataSource();
+ final String contentType = getBaseMimeType(dataSource.getContentType());
+ final byte[] content = MimeMessageParser.getContent(dataSource.getInputStream());
+ final ByteArrayDataSource result = new ByteArrayDataSource(content, contentType);
+ final String dataSourceName = getDataSourceName(part, dataSource);
+
+ result.setName(dataSourceName);
+ return result;
+ }
+
+ /**
+ * Determines the name of the data source if it is not already set.
+ *
+ * @param part the mail part
+ * @param dataSource the data source
+ * @return the name of the data source or {@code null} if no name can be determined
+ * @throws MessagingException accessing the part failed
+ * @throws UnsupportedEncodingException decoding the text failed
+ */
+ private static String getDataSourceName(final Part part, final DataSource dataSource)
+ throws MessagingException, UnsupportedEncodingException {
+ String result = dataSource.getName();
+
+ if (result == null || result.length() == 0) {
+ result = part.getFileName();
+ }
+
+ if (result != null && result.length() > 0) {
+ result = MimeUtility.decodeText(result);
+ } else {
+ result = null;
+ }
+
+ return result;
+ }
+
+ /**
+ * Read the content of the input stream.
+ *
+ * @param is the input stream to process
+ * @return the content of the input stream
+ * @throws IOException reading the input stream failed
+ */
+ private static byte[] getContent(final InputStream is)
+ throws IOException {
+ int ch;
+ final byte[] result;
+
+ final ByteArrayOutputStream os = new ByteArrayOutputStream();
+ final BufferedInputStream isReader = new BufferedInputStream(is);
+ final BufferedOutputStream osWriter = new BufferedOutputStream(os);
+
+ while ((ch = isReader.read()) != -1) {
+ osWriter.write(ch);
+ }
+
+ osWriter.flush();
+ result = os.toByteArray();
+ osWriter.close();
+
+ return result;
+ }
+
+ /**
+ * Parses the mimeType.
+ *
+ * @param fullMimeType the mime type from the mail api
+ * @return the real mime type
+ */
+ private static String getBaseMimeType(final String fullMimeType) {
+ final int pos = fullMimeType.indexOf(';');
+ if (pos >= 0) {
+ return fullMimeType.substring(0, pos);
+ }
+ return fullMimeType;
+ }
+
+ /**
+ * @return {@link #cidMap}
+ */
+ public Map getCidMap() {
+ return cidMap;
+ }
+
+ /**
+ * @return {@link #headers}
+ */
+ public Map getHeaders() {
+ return headers;
+ }
+
+ /**
+ * @return {@link #plainContent}
+ */
+ public String getPlainContent() {
+ return plainContent;
+ }
+
+ /**
+ * @return {@link #attachmentList}
+ */
+ public Map getAttachmentList() {
+ return attachmentList;
+ }
+
+ /**
+ * @return {@link #htmlContent}
+ */
+ public String getHtmlContent() {
+ return htmlContent;
+ }
+
}
\ No newline at end of file
diff --git a/src/main/java/org/simplejavamail/mailer/internal/mailsender/MimeMessageHelper.java b/src/main/java/org/simplejavamail/mailer/internal/mailsender/MimeMessageHelper.java
index 1128e1d36..120f94fa9 100644
--- a/src/main/java/org/simplejavamail/mailer/internal/mailsender/MimeMessageHelper.java
+++ b/src/main/java/org/simplejavamail/mailer/internal/mailsender/MimeMessageHelper.java
@@ -19,8 +19,10 @@
import java.security.spec.InvalidKeySpecException;
import java.util.Date;
import java.util.Map;
+import java.util.UUID;
import static java.lang.String.format;
+import static org.simplejavamail.internal.util.MiscUtil.valueNullOrEmpty;
/**
* Helper class that deals with javax.mail RFC MimeMessage stuff, as well as DKIM signing.
@@ -202,19 +204,48 @@ private static void setHeaders(final Email email, final Message message)
private static BodyPart getBodyPartFromDatasource(final AttachmentResource attachmentResource, final String dispositionType)
throws MessagingException {
final BodyPart attachmentPart = new MimeBodyPart();
- final DataSource dataSource = attachmentResource.getDataSource();
// setting headers isn't working nicely using the javax mail API, so let's do that manually
- final String resourceName = attachmentResource.getName();
- final boolean dataSourceNameProvided = dataSource.getName() != null && !dataSource.getName().isEmpty();
- final String fileName = dataSourceNameProvided ? dataSource.getName() : resourceName;
+ String resourceName = determineResourceName(attachmentResource, false);
+ String fileName = determineResourceName(attachmentResource, true);
attachmentPart.setDataHandler(new DataHandler(attachmentResource.getDataSource()));
attachmentPart.setFileName(fileName);
- attachmentPart.setHeader("Content-Type", dataSource.getContentType() + "; filename=" + fileName + "; name=" + fileName);
+ String contentType = attachmentResource.getDataSource().getContentType();
+ attachmentPart.setHeader("Content-Type", contentType + "; filename=" + fileName + "; name=" + resourceName);
attachmentPart.setHeader("Content-ID", format("<%s>", resourceName));
attachmentPart.setDisposition(dispositionType + "; size=0");
return attachmentPart;
}
+ /**
+ * Determines the right resource name and optionally attaches the correct extension to the name.
+ */
+ static String determineResourceName(AttachmentResource attachmentResource, boolean includeExtension) {
+ final String datasourceName = attachmentResource.getDataSource().getName();
+
+ String resourceName;
+
+ if (!valueNullOrEmpty(attachmentResource.getName())) {
+ resourceName = attachmentResource.getName();
+ } else if (!valueNullOrEmpty(datasourceName)) {
+ resourceName = datasourceName;
+ } else {
+ resourceName = "resource" + UUID.randomUUID();
+ }
+ if (includeExtension && !valueNullOrEmpty(datasourceName)) {
+ String possibleFilename = datasourceName;
+ if (possibleFilename.contains(".")) {
+ String extension = possibleFilename.substring(possibleFilename.lastIndexOf("."), possibleFilename.length());
+ if (!resourceName.endsWith(extension)) {
+ resourceName += extension;
+ }
+ }
+ } else if (!includeExtension && resourceName.contains(".") && resourceName.equals(datasourceName)) {
+ String extension = resourceName.substring(resourceName.lastIndexOf("."), resourceName.length());
+ resourceName = resourceName.replace(extension, "");
+ }
+ return resourceName;
+ }
+
/**
* Primes the {@link MimeMessage} instance for signing with DKIM. The signing itself is performed by {@link DkimMessage} and {@link DkimSigner}
* during the physical sending of the message.
diff --git a/src/test/java/org/simplejavamail/mailer/internal/mailsender/MimeMessageHelperTest.java b/src/test/java/org/simplejavamail/mailer/internal/mailsender/MimeMessageHelperTest.java
new file mode 100644
index 000000000..077351249
--- /dev/null
+++ b/src/test/java/org/simplejavamail/mailer/internal/mailsender/MimeMessageHelperTest.java
@@ -0,0 +1,76 @@
+package org.simplejavamail.mailer.internal.mailsender;
+
+import org.junit.Test;
+import org.simplejavamail.email.AttachmentResource;
+
+import javax.mail.util.ByteArrayDataSource;
+import java.io.IOException;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class MimeMessageHelperTest {
+
+ @Test
+ public void determineResourceName1()
+ throws IOException {
+ AttachmentResource resource1 = new AttachmentResource(null, getDataSource("blahblah"));
+ assertThat(MimeMessageHelper.determineResourceName(resource1, false)).isEqualTo("blahblah");
+ assertThat(MimeMessageHelper.determineResourceName(resource1, true)).isEqualTo("blahblah");
+ }
+
+ @Test
+ public void determineResourceName2()
+ throws IOException {
+ AttachmentResource resource2 = new AttachmentResource(null, getDataSource("blahblah.txt"));
+ assertThat(MimeMessageHelper.determineResourceName(resource2, false)).isEqualTo("blahblah");
+ assertThat(MimeMessageHelper.determineResourceName(resource2, true)).isEqualTo("blahblah.txt");
+ }
+
+ @Test
+ public void determineResourceName3()
+ throws IOException {
+ AttachmentResource resource3 = new AttachmentResource("the resource", getDataSource(null));
+ assertThat(MimeMessageHelper.determineResourceName(resource3, false)).isEqualTo("the resource");
+ assertThat(MimeMessageHelper.determineResourceName(resource3, true)).isEqualTo("the resource");
+ }
+
+ @Test
+ public void determineResourceName4()
+ throws IOException {
+ AttachmentResource resource4 = new AttachmentResource("the resource", getDataSource("blahblah.txt"));
+ assertThat(MimeMessageHelper.determineResourceName(resource4, false)).isEqualTo("the resource");
+ assertThat(MimeMessageHelper.determineResourceName(resource4, true)).isEqualTo("the resource.txt");
+ }
+
+ @Test
+ public void determineResourceName5()
+ throws IOException {
+ AttachmentResource resource5 = new AttachmentResource("the resource", getDataSource("blahblah"));
+ assertThat(MimeMessageHelper.determineResourceName(resource5, false)).isEqualTo("the resource");
+ assertThat(MimeMessageHelper.determineResourceName(resource5, true)).isEqualTo("the resource");
+ }
+
+ @Test
+ public void determineResourceName6()
+ throws IOException {
+ AttachmentResource resource6 = new AttachmentResource("the resource.txt", getDataSource("blahblah.txt"));
+ assertThat(MimeMessageHelper.determineResourceName(resource6, false)).isEqualTo("the resource.txt");
+ assertThat(MimeMessageHelper.determineResourceName(resource6, true)).isEqualTo("the resource.txt");
+ }
+
+ @Test
+ public void determineResourceName7()
+ throws IOException {
+ AttachmentResource resource7 = new AttachmentResource("the resource.txt", getDataSource("blahblah"));
+ assertThat(MimeMessageHelper.determineResourceName(resource7, false)).isEqualTo("the resource.txt");
+ assertThat(MimeMessageHelper.determineResourceName(resource7, true)).isEqualTo("the resource.txt");
+ }
+
+ private ByteArrayDataSource getDataSource(String name)
+ throws IOException {
+ ByteArrayDataSource ds = new ByteArrayDataSource("", "text/text");
+ ds.setName(name);
+ return ds;
+ }
+
+}
\ No newline at end of file