This is an automated email from the ASF dual-hosted git repository.

ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-email.git


The following commit(s) were added to refs/heads/master by this push:
     new 88567932 MultiPartEmail attach methods now throw an IOException if the 
given file is a directory
88567932 is described below

commit 88567932dc17dae04564e564d9333682a98a2dd8
Author: Gary Gregory <[email protected]>
AuthorDate: Wed Feb 11 19:27:36 2026 -0500

    MultiPartEmail attach methods now throw an IOException if the given file
    is a directory
---
 .../org/apache/commons/mail2/core/EmailUtils.java  | 43 ++++++++++++++++++++++
 .../commons/mail2/jakarta/MultiPartEmail.java      | 17 ++-------
 .../commons/mail2/jakarta/MultiPartEmailTest.java  |  8 ++++
 .../apache/commons/mail2/javax/MultiPartEmail.java | 20 +++-------
 .../commons/mail2/javax/MultiPartEmailTest.java    |  8 ++++
 src/changes/changes.xml                            |  1 +
 6 files changed, 69 insertions(+), 28 deletions(-)

diff --git 
a/commons-email2-core/src/main/java/org/apache/commons/mail2/core/EmailUtils.java
 
b/commons-email2-core/src/main/java/org/apache/commons/mail2/core/EmailUtils.java
index 4f070ae9..a6210f79 100644
--- 
a/commons-email2-core/src/main/java/org/apache/commons/mail2/core/EmailUtils.java
+++ 
b/commons-email2-core/src/main/java/org/apache/commons/mail2/core/EmailUtils.java
@@ -17,11 +17,16 @@
 
 package org.apache.commons.mail2.core;
 
+import java.io.File;
+import java.io.IOException;
 import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
 import java.util.BitSet;
 import java.util.Collection;
 import java.util.Locale;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Random;
 
 /**
@@ -86,6 +91,44 @@ public final class EmailUtils {
         SAFE_URL.set('@');
     }
 
+    /**
+     * Checks that the given file exists and is not a directory.
+     *
+     * @param file the file to check.
+     * @return the given file if it exists and is not a directory.
+     * @throws IOException if the given file does not exist or is a directory.
+     * @since 2.0.0-M2
+     */
+    public static File check(final File file) throws IOException {
+        Objects.requireNonNull(file, "file");
+        if (!file.exists()) {
+            throw new IOException("\"" + file + "\" does not exist");
+        }
+        if (file.isDirectory()) {
+            throw new IOException("\"" + file + "\" is a directory");
+        }
+        return file;
+    }
+
+    /**
+     * Checks that the given file exists and is not a directory.
+     *
+     * @param file the file to check.
+     * @return the given file if it exists and is not a directory.
+     * @throws IOException if the given file does not exist or is a directory.
+     * @since 2.0.0-M2
+     */
+    public static Path check(final Path file) throws IOException {
+        Objects.requireNonNull(file, "file");
+        if (!Files.exists(file)) {
+            throw new IOException("\"" + file + "\" does not exist");
+        }
+        if (Files.isDirectory(file)) {
+            throw new IOException("\"" + file + "\" is a directory");
+        }
+        return file;
+    }
+
     /**
      * Encodes an input string according to RFC 2392. Unsafe characters are 
escaped.
      *
diff --git 
a/commons-email2-jakarta/src/main/java/org/apache/commons/mail2/jakarta/MultiPartEmail.java
 
b/commons-email2-jakarta/src/main/java/org/apache/commons/mail2/jakarta/MultiPartEmail.java
index 4f7cea31..cf26ad58 100644
--- 
a/commons-email2-jakarta/src/main/java/org/apache/commons/mail2/jakarta/MultiPartEmail.java
+++ 
b/commons-email2-jakarta/src/main/java/org/apache/commons/mail2/jakarta/MultiPartEmail.java
@@ -21,7 +21,6 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.UnsupportedEncodingException;
 import java.net.URL;
-import java.nio.file.Files;
 import java.nio.file.OpenOption;
 import java.nio.file.Path;
 import java.util.Objects;
@@ -202,10 +201,7 @@ public class MultiPartEmail extends Email {
             String fileName = null;
             try {
                 fileName = attachment.getPath();
-                final File file = new File(fileName);
-                if (!file.exists()) {
-                    throw new IOException("\"" + fileName + "\" does not 
exist");
-                }
+                final File file = EmailUtils.check(new File(fileName));
                 result = attach(new FileDataSource(file), 
attachment.getName(), attachment.getDescription(), attachment.getDisposition());
             } catch (final IOException e) {
                 throw new EmailException("Cannot attach file \"" + fileName + 
"\"", e);
@@ -225,14 +221,11 @@ public class MultiPartEmail extends Email {
      * @since 1.3
      */
     public MultiPartEmail attach(final File file) throws EmailException {
-        final String fileName = file.getAbsolutePath();
         try {
-            if (!file.exists()) {
-                throw new IOException("\"" + fileName + "\" does not exist");
-            }
+            EmailUtils.check(file);
             return attach(new FileDataSource(file), file.getName(), null, 
EmailAttachment.ATTACHMENT);
         } catch (final IOException e) {
-            throw new EmailException("Cannot attach file \"" + fileName + 
"\"", e);
+            throw new EmailException("Cannot attach file \"" + file + "\"", e);
         }
     }
 
@@ -248,9 +241,7 @@ public class MultiPartEmail extends Email {
     public MultiPartEmail attach(final Path file, final OpenOption... options) 
throws EmailException {
         final Path fileName = file.toAbsolutePath();
         try {
-            if (!Files.exists(file)) {
-                throw new IOException("\"" + fileName + "\" does not exist");
-            }
+            EmailUtils.check(file);
             return attach(new PathDataSource(file, 
FileTypeMap.getDefaultFileTypeMap(), options), 
Objects.toString(file.getFileName(), null), null,
                     EmailAttachment.ATTACHMENT);
         } catch (final IOException e) {
diff --git 
a/commons-email2-jakarta/src/test/java/org/apache/commons/mail2/jakarta/MultiPartEmailTest.java
 
b/commons-email2-jakarta/src/test/java/org/apache/commons/mail2/jakarta/MultiPartEmailTest.java
index 183469f6..2b304925 100644
--- 
a/commons-email2-jakarta/src/test/java/org/apache/commons/mail2/jakarta/MultiPartEmailTest.java
+++ 
b/commons-email2-jakarta/src/test/java/org/apache/commons/mail2/jakarta/MultiPartEmailTest.java
@@ -136,6 +136,10 @@ class MultiPartEmailTest extends AbstractEmailTest {
         final EmailAttachment attachment4 = new EmailAttachment();
         attachment4.setPath("");
         assertThrows(EmailException.class, () -> email.attach(attachment4));
+        attachment4.setPath("ThisFileDoesNotExist.txt");
+        assertThrows(EmailException.class, () -> email.attach(attachment4));
+        attachment4.setPath("target"); // a directory, not a file
+        assertThrows(EmailException.class, () -> email.attach(attachment4));
     }
 
     @Test
@@ -179,6 +183,10 @@ class MultiPartEmailTest extends AbstractEmailTest {
         final EmailAttachment attachment4 = new EmailAttachment();
         attachment4.setPath("");
         assertThrows(EmailException.class, () -> email.attach(attachment4));
+        attachment4.setPath("ThisFileDoesNotExist.txt");
+        assertThrows(EmailException.class, () -> email.attach(attachment4));
+        attachment4.setPath("target"); // a directory, not a file
+        assertThrows(EmailException.class, () -> email.attach(attachment4));
     }
 
     /** TODO implement test for GetContainer */
diff --git 
a/commons-email2-javax/src/main/java/org/apache/commons/mail2/javax/MultiPartEmail.java
 
b/commons-email2-javax/src/main/java/org/apache/commons/mail2/javax/MultiPartEmail.java
index 252b0e18..236d60f7 100644
--- 
a/commons-email2-javax/src/main/java/org/apache/commons/mail2/javax/MultiPartEmail.java
+++ 
b/commons-email2-javax/src/main/java/org/apache/commons/mail2/javax/MultiPartEmail.java
@@ -21,7 +21,6 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.UnsupportedEncodingException;
 import java.net.URL;
-import java.nio.file.Files;
 import java.nio.file.OpenOption;
 import java.nio.file.Path;
 import java.util.Objects;
@@ -202,7 +201,7 @@ public class MultiPartEmail extends Email {
             String fileName = null;
             try {
                 fileName = attachment.getPath();
-                final File file = new File(fileName);
+                final File file = EmailUtils.check(new File(fileName));
                 if (!file.exists()) {
                     throw new IOException("\"" + fileName + "\" does not 
exist");
                 }
@@ -225,14 +224,11 @@ public class MultiPartEmail extends Email {
      * @since 1.3
      */
     public MultiPartEmail attach(final File file) throws EmailException {
-        final String fileName = file.getAbsolutePath();
         try {
-            if (!file.exists()) {
-                throw new IOException("\"" + fileName + "\" does not exist");
-            }
+            EmailUtils.check(file);
             return attach(new FileDataSource(file), file.getName(), null, 
EmailAttachment.ATTACHMENT);
         } catch (final IOException e) {
-            throw new EmailException("Cannot attach file \"" + fileName + 
"\"", e);
+            throw new EmailException("Cannot attach file \"" + file + "\"", e);
         }
     }
 
@@ -246,15 +242,12 @@ public class MultiPartEmail extends Email {
      * @since 1.6.0
      */
     public MultiPartEmail attach(final Path file, final OpenOption... options) 
throws EmailException {
-        final Path fileName = file.toAbsolutePath();
         try {
-            if (!Files.exists(file)) {
-                throw new IOException("\"" + fileName + "\" does not exist");
-            }
+            EmailUtils.check(file);
             return attach(new PathDataSource(file, 
FileTypeMap.getDefaultFileTypeMap(), options), 
Objects.toString(file.getFileName(), null), null,
                     EmailAttachment.ATTACHMENT);
         } catch (final IOException e) {
-            throw new EmailException("Cannot attach file \"" + fileName + 
"\"", e);
+            throw new EmailException("Cannot attach file \"" + file + "\"", e);
         }
     }
 
@@ -307,7 +300,6 @@ public class MultiPartEmail extends Email {
                 // before a multipart message can be sent, we must make sure 
that
                 // the content for the main body part was actually set. If not,
                 // an IOException will be thrown during super.send().
-
                 final BodyPart body = getPrimaryBodyPart();
                 try {
                     body.getContent();
@@ -318,11 +310,9 @@ public class MultiPartEmail extends Email {
                     // throw new EmailException(e);
                 }
             }
-
             if (subType != null) {
                 getContainer().setSubType(subType);
             }
-
             super.buildMimeMessage();
         } catch (final MessagingException e) {
             throw new EmailException(e);
diff --git 
a/commons-email2-javax/src/test/java/org/apache/commons/mail2/javax/MultiPartEmailTest.java
 
b/commons-email2-javax/src/test/java/org/apache/commons/mail2/javax/MultiPartEmailTest.java
index 085e8def..2f2bcfbf 100644
--- 
a/commons-email2-javax/src/test/java/org/apache/commons/mail2/javax/MultiPartEmailTest.java
+++ 
b/commons-email2-javax/src/test/java/org/apache/commons/mail2/javax/MultiPartEmailTest.java
@@ -136,6 +136,10 @@ class MultiPartEmailTest extends AbstractEmailTest {
         final EmailAttachment attachment4 = new EmailAttachment();
         attachment4.setPath("");
         assertThrows(EmailException.class, () -> email.attach(attachment4));
+        attachment4.setPath("ThisFileDoesNotExist.txt");
+        assertThrows(EmailException.class, () -> email.attach(attachment4));
+        attachment4.setPath("target"); // a directory, not a file
+        assertThrows(EmailException.class, () -> email.attach(attachment4));
     }
 
     @Test
@@ -179,6 +183,10 @@ class MultiPartEmailTest extends AbstractEmailTest {
         final EmailAttachment attachment4 = new EmailAttachment();
         attachment4.setPath("");
         assertThrows(EmailException.class, () -> email.attach(attachment4));
+        attachment4.setPath("ThisFileDoesNotExist.txt");
+        assertThrows(EmailException.class, () -> email.attach(attachment4));
+        attachment4.setPath("target"); // a directory, not a file
+        assertThrows(EmailException.class, () -> email.attach(attachment4));
     }
 
     /** TODO implement test for GetContainer */
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 59b2b6c3..2b63b34f 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -27,6 +27,7 @@
       <!-- FIX -->
       <action type="update" due-to="Derek Wickern, Gary Gregory" 
dev="ggregory">Handle IllegalArgumentException thrown for invalid email address 
#328.</action>
       <action type="fix" dev="ggregory" due-to="Gary Gregory">Fix Apache RAT 
plugin console warnings.</action>
+      <action type="fix" dev="ggregory" due-to="Gary Gregory, Henri Cook, 
Sebb">MultiPartEmail attach methods now throw an IOException if the given file 
is a directory.</action>
       <!-- UPDATE -->
       <action type="update" due-to="Gary Gregory, Dependabot" 
dev="ggregory">Bump commons-parent from 72 to 96 #279, #293, #297, #304, #350, 
#376, #386, #390, #392.</action>
       <action type="update" due-to="Gary Gregory" dev="ggregory">Bump 
org.mockito:mockito-core from 5.13.0 to 5.21.0 #290, #296, #302, #319, #336, 
#338, #344, #353, #366.</action>

Reply via email to