Can someone please point out what I'm doing wrong here.
I have a small weather app that generates and sends an HTML email. With my code below, everything works fine when I run it from Eclipse. My email gets generated, it's able to access my image resources and it sends the email with the included attachment.
However, when I build the executable jar by running mvn install and run the jar using java -jar NameOfMyJar.jar I get java.io.FileNotFound Exceptions for my image resource.
I know that I have to be doing something wrong with how I'm accessing my image resources, I just don't understand why it works fine when it's not packaged, but bombs out whenever I package it into a jar.
Any advice is very much appreciated it.
My project layout
How I'm accessing my image resource
//Setup the ATTACHMENTS
MimeBodyPart attachmentsPart = new MimeBodyPart();
try {
attachmentsPart.attachFile("resources/Cloudy_Day.png");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
The StackTrace
Exception in thread "main" java.lang.RuntimeException: javax.mail.MessagingException: IOException while sending message;
nested exception is:
java.io.FileNotFoundException: resources/Cloudy_Day.png (No such file or directory)
at Utilities.SendEmailUsingGmailSMTP.SendTheEmail(SendEmailUsingGmailSMTP.java:139)
at Utilities.SendEmailUsingGmailSMTP.SendWeatherEmail(SendEmailUsingGmailSMTP.java:66)
at Weather.Main.start(Main.java:43)
at Weather.Main.main(Main.java:23)
Caused by: javax.mail.MessagingException: IOException while sending message;
nested exception is:
java.io.FileNotFoundException: resources/Cloudy_Day.png (No such file or directory)
at com.sun.mail.smtp.SMTPTransport.sendMessage(SMTPTransport.java:1167)
at javax.mail.Transport.send0(Transport.java:195)
at javax.mail.Transport.send(Transport.java:124)
at Utilities.SendEmailUsingGmailSMTP.SendTheEmail(SendEmailUsingGmailSMTP.java:134)
... 3 more
Caused by: java.io.FileNotFoundException: resources/Cloudy_Day.png (No such file or directory)
at java.io.FileInputStream.open(Native Method)
at java.io.FileInputStream.<init>(FileInputStream.java:146)
at javax.activation.FileDataSource.getInputStream(FileDataSource.java:97)
at javax.activation.DataHandler.writeTo(DataHandler.java:305)
at javax.mail.internet.MimeBodyPart.writeTo(MimeBodyPart.java:1485)
at javax.mail.internet.MimeBodyPart.writeTo(MimeBodyPart.java:865)
at javax.mail.internet.MimeMultipart.writeTo(MimeMultipart.java:462)
at com.sun.mail.handlers.multipart_mixed.writeTo(multipart_mixed.java:103)
at javax.activation.ObjectDataContentHandler.writeTo(DataHandler.java:889)
at javax.activation.DataHandler.writeTo(DataHandler.java:317)
at javax.mail.internet.MimeBodyPart.writeTo(MimeBodyPart.java:1485)
at javax.mail.internet.MimeMessage.writeTo(MimeMessage.java:1773)
at com.sun.mail.smtp.SMTPTransport.sendMessage(SMTPTransport.java:1119)
... 6 more
No, resources work perfectly well in a JAR. Just don't treat a resource as a File, because it isn't one. Instead, use the getResourceAsStream() method and you'll have an InputStream from which you can read the contents of the resource.
If you can't run jar files on your Windows 10 PC, you might need to reinstall Java Runtime Environment. When JAR files are not opening, another great method is to simply use a universal file opener. Alternatively, some reported that turning your JAR file into a BAT file worked perfectly.
Others are correct with the use of getResourceAsStream
, but the path is a little tricky. You see the little package icon in the resources
folder? That signifies that all the files in the resource
folder will be put into the root of the classpath. Just like all the packages in src/main/java
are put in the root. So you would take out the resources
from the path
InputStream is = getClass().getResourceAsStream("/Cloudy_Day.png");
An aside: Maven has a file structure conventions. Class path resources are usually put into src/main/resources
. If you create a resources
dir in the src/main
, Eclipse should automatically pick it up, and create the little package icon for a path src/main/resource
that you should see in the project explorer. These files would also go to the root and could be accessed the same way. I would fix the file structure to follow this convention.
Note: A (As suggested by Bill Shannon, this is incorrect). As mentioned in his comment belowMimeBodyPart
, can be Constructed from an InputStream
"You can also attach the data using"
mbp.setDataHandler(new DataHandler(new ByteArrayDataSource(
this.getClass().getResourceAsStream("/Cloudy_Day.png", "image/png"))));
You can't access resources inside a JAR file as a File, only read them as an InputStream: getResourceAsStream()
.
As the MimeBodyPart has no attach()
method for an InputStream, the easiest way should be to read your resources and write them to temp files, then attach these files.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With