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