I am working on a project using JavaMail. I want to access my Gmail inbox and get the messages. I look for a specific message by checking the subject. This message has an attachment which i save.The program works fine on the first run. The problem is that once I run the program, any subsequent runs can not see the message. It does not appear as a part of the folder's messages. If I go to the gmail account and set "Enable POP for all mail (even mail that's already been downloaded)" (whihc was the setting from the beginning) I can see the message once more before it again stops appearing in the folder. I dont understand, any help would be great.
Here is my code that gets the messages:
Session session2 = Session.getDefaultInstance(props2, null);
Store store = session2.getStore("pop3s");
store.connect(getHost, username, password);
Folder folder = store.getFolder("INBOX");
folder.open(Folder.READ_ONLY);
System.out.println(folder.getMessageCount());
Message messages[] = folder.getMessages();
for (Message message : messages) {
System.out.println(message.getSubject());
if (message.getSubject().equalsIgnoreCase("Input File")) {
if (message.getContent() instanceof Multipart) {
Multipart multipart = (Multipart) message.getContent();
for (int i = 0, n = multipart.getCount(); i < n; i++) {
Part part = multipart.getBodyPart(i);
String disposition = part.getDisposition();
if ((disposition != null) && ((disposition.equals(Part.ATTACHMENT) || (disposition.equals(Part.INLINE))))) {
File f = saveFile(part.getFileName(), part.getInputStream());
System.out.println(f.getPath());
}
}
}
}
}
folder.close(false);
store.close();
}
The saveFile method:
public static File saveFile(String filename, InputStream input) throws FileNotFoundException, IOException {
File file = new File(filename);
for (int i = 0; file.exists(); i++) {
file = new File(filename + i);
}
FileOutputStream fos = new FileOutputStream(file);
BufferedOutputStream bos = new BufferedOutputStream(fos);
BufferedInputStream bis = new BufferedInputStream(input);
int aByte;
while ((aByte = bis.read()) != -1) {
bos.write(aByte);
}
bos.flush();
bos.close();
bis.close();
return file;
}
I tried switching my code to using imap and now it seems to be working. I guess my problem has something to do with pop3 and gmail.
The code is almost correct and it helped me very much. The Part.Attachment ="attachment" but the String disposition = "ATTACHMENT"
Only replace the part
if ((disposition != null) && ((disposition.equals(Part.ATTACHMENT) || (disposition.equals(Part.INLINE))))) {
File f = saveFile(part.getFileName(), part.getInputStream());
System.out.println(f.getPath());
}
with
if ((disposition != null) && ((disposition.toLowaerCase().equals(Part.ATTACHMENT) || (disposition.equals(Part.INLINE))))) {
File f = saveFile(part.getFileName(), part.getInputStream());
System.out.println(f.getPath());
}
Related
I am attempting to build a client that uses the javax.mail API to read email messages, including attachments. My initial thought was to use the Tika library. When that produced an unexpected result (please refer to code and details below), I tried using a variation of the code presented in this question.
My function for reading emails:
// Reference: https://www.tutorialspoint.com/javamail_api/javamail_api_checking_emails.htm
public class CheckingMails {
public static void check(String host, String storeType, String user, String password) {
try {
// create properties field
Properties properties = new Properties();
properties.put("mail.pop3.host", host);
properties.put("mail.pop3.port", "110");
Session emailSession = Session.getInstance(properties);
Store store = emailSession.getStore("pop3");
store.connect(host, user, password);
Folder emailFolder = store.getFolder("INBOX");
emailFolder.open(Folder.READ_WRITE);
// retrieve the messages from the folder in an array and print it
Message[] messages = emailFolder.getMessages();
System.out.println("messages.length---" + messages.length);
for (int i = 0, n = messages.length; i < n; i++) {
Message message = messages[i];
Object content = message.getContent();
if (content instanceof java.lang.String) {
System.out.println((String) content);
} else if (content instanceof Multipart) {
Multipart mp = (Multipart) content;
for (int j = 0; j < mp.getCount(); j++) {
Part part = mp.getBodyPart(j);
String disposition = part.getDisposition();
if (disposition == null) {
// Check if plain
MimeBodyPart mbp = (MimeBodyPart) part;
if (mbp.isMimeType("text/plain")) {
System.out.println("Mime type is plain");
System.out.println((String) mbp.getContent());
} else {
// Special non-attachment cases here of
// image/gif, text/html, ...
System.out.println("File name is " + part.getFileName());
}
} else if ((disposition != null)
&& (disposition.equals(Part.ATTACHMENT) || disposition.equals(Part.INLINE))) {
// Check if plain
MimeBodyPart mbp = (MimeBodyPart) part;
if (mbp.isMimeType("text/plain")) {
System.out.println("Mime type is plain");
System.out.println((String) mbp.getContent());
} else {
System.out.println("Save file " + part.getFileName());
}
}
}
}
System.out.println("Tika results " + parseMsg(message));
}
// close the store and folder objects
emailFolder.close(false);
store.close();
} catch (MessagingException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
When I test the program by sending a test message with a simple CSV as an attachment, the Tika parser outputs the following (truncated for brevity):
------=_NextPart_000_0028_01D47C16.81FB45C0
Content-Type: application/ms-tnef;
name="winmail.dat"
Content-Transfer-Encoding: base64
Content-Disposition: attachment;
filename="winmail.dat"
eJ8+IhUSAQaQCAAEAAAAAAABAAEAAQeQBgAIAAAA5AQAAAAAAADoAAEIgAcAGAAAAElQTS5NaWNy
b3NvZnQgTWFpbC5Ob3RlADEIAQOQBgCgDQAANgAAAAsAAgABAAAAAwAmAAAAAAALACkAAAAAAB4A
cAABAAAABQAAAFRlc3QAAAAAAgFxAAEAAAAWAAAAAdR8SMswwghurPF+SpeO8uRrTzrhCgAACwAB
DgAAAAACAQoOAQAAABg.....
------=_NextPart_000_0028_01D47C16.81FB45C0--
The other portion of the code (that checks for the message's disposition), outputs something similar to the following:
messages.length---1
Mime type is plain
Email Boday
Save file winmail.dat
Why is the application reading/recognizing winmail.dat and not the attachment that was actually sent with the message (a CSV file)?
Thanks for any help.
I have an existing code that downloads and processes some emails correctly.
The email to process must have one or more xml as attachment, now I'm migrating this process from the current standard mail account to a certified system that wrap that mail into a new email.
So, instead of a flat email with one xml attachment, I have to parse an email with an XML (the certified) and an EML (the message that I should process).
In short, my code is like the following:
private void processMessage(final Message message) {
try {
final String contentType = message.getContentType();
if (contentType.contains("multipart")) {
final Multipart multiPart = (Multipart) message.getContent();
for (int i = 0; i < multiPart.getCount(); i++) {
final MimeBodyPart part = (MimeBodyPart) multiPart.getBodyPart(i);
/**************************************************************
* HERE I CAN'T GET THE EML (and its attachments) FROM 'part' *
**************************************************************/
if (Part.ATTACHMENT.equalsIgnoreCase(part.getDisposition())) {
processAttachment(part);
}
}
}
} [...cutted...]
}
private void processAttachment(final MimeBodyPart part) throws IOException, MessagingException {
final InputStream input = getReusableInputStream(part);
if (part.getFileName() != null && isXmlType(part.getContentType())) {
processXml(input);
}
}
I should modify it, in order to parse the EML and get the attachments recursively, but I'm missing the big picture.
UPDATE: I've modified the processAttachment method (but it still doesn't work):
private void processAttachment(final Multipart multipart) {
try {
for (int i = 0; i < multipart.getCount(); i++) {
final BodyPart bodyPart = multipart.getBodyPart(i);
if (bodyPart.getContent() instanceof Multipart) {
// part-within-a-part, do some recursion...
extractAttachment((Multipart) bodyPart.getContent());
}
System.out.println("Filename: " + bodyPart.getFileName());
System.out.println("ct: " + bodyPart.getContentType());
final boolean isXml = bodyPart.getFileName() != null && isXmlType(bodyPart.getContentType());
if (isXml) {
final InputStream inputStream = getReusableInputStream(bodyPart);
processXMLAttachment(inputStream);
}
}
} [cutted]
}
The output is:
Filename: null
ct: TEXT/PLAIN; charset=iso-8859-1
Filename: null
ct: TEXT/HTML; charset=iso-8859-1
Filename: daticert.xml
ct: APPLICATION/XML; name=daticert.xml
Filename: postacert.eml
ct: MESSAGE/RFC822; name=postacert.eml
Filename: smime.p7s
ct: APPLICATION/X-PKCS7-SIGNATURE; name=smime.p7s
From the output, I can see that the system only scaned the first level attachments daticert.xml and postacert.eml but it didn't find the nested attachments.
More specifically, I have to read the content of:
Filename: postacert.eml
ct: MESSAGE/RFC822; name=postacert.eml
Any help, please?
Thanks
Well, I solved by checking the class of any MimePart, and I found that nested messages are type of IMAPNestedMessage, so on this kind of object I recursively call the main method processMessage:
private void processAttachment(final Multipart multipart) {
try {
for (int i = 0; i < multipart.getCount(); i++) {
final BodyPart bodyPart = multipart.getBodyPart(i);
// BEGIN - Added this part
System.out.println("CLASS bodyPart: " + bodyPart.getContent().getClass());
if (bodyPart.getContent() instanceof IMAPNestedMessage) {
processMessage((IMAPNestedMessage) bodyPart.getContent());
} else {
// END - Added this part
if (bodyPart.getContent() instanceof Multipart) {
processAttachment((Multipart) bodyPart.getContent());
} else {
final boolean isXml = bodyPart.getFileName() != null && isXmlType(bodyPart.getContentType());
if (isXml) {
final InputStream inputStream = getReusableInputStream(bodyPart);
processXMLAttachment(inputStream);
}
}
}
}
} catch (final Exception e) {
sendMailService.sendMailForImportINPSFailed("metodo processAttachment()", e);
e.printStackTrace();
}
}
And now it works fine.
Whats the correct way of sending and getting files and save it to a folder?
I am sending a post from Postman with body form-data: 2 keys 'uploadfile' each with one zip.
This code gets only one zip and save it, ignoring the second zip.
How can I implement it to save both files?
Also. Should I send 2 files in one key? or each file in separated keys?
#RequestMapping(value = "/api/uploadFile", method = RequestMethod.POST)
#ResponseBody
public ResponseEntity<?> uploadFile(
#RequestParam("uploadfile") MultipartFile uploadfile) {
try {
// Get the filename and build the local file path (be sure that the
// application have write permissions on such directory)
String filename = uploadfile.getOriginalFilename();
String directory = "C://Develop//files";
String filepath = Paths.get(directory, filename).toString();
filenameZip = "c:/Develop/files/"+filename;
directoryZip = "c:/Develop/files";
// Save the file locally
BufferedOutputStream stream =
new BufferedOutputStream(new FileOutputStream(new File(filepath)));
stream.write(uploadfile.getBytes());
stream.close();
} catch (Exception e) {
System.out.println(e.getMessage());
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
// unzip(filenameZip, directoryZip);
return new ResponseEntity<>(HttpStatus.OK);
} // method uploadFile
Postman Log:
var data = new FormData();
data.append("uploadfile", "pasta1.zip");
data.append("uploadfile", "pasta2.zip");
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
xhr.addEventListener("readystatechange", function () {
if (this.readyState === 4) {
console.log(this.responseText);
}
});
xhr.open("POST", "http://localhost:8080/api/uploadFile");
xhr.setRequestHeader("authorization", "Basic b3BlcmF0aW9uczpvcGVyYXRpb25z");
xhr.setRequestHeader("cache-control", "no-cache");
xhr.setRequestHeader("postman-token", "e7b6fcae-4a49-de34-ba7c-efd412fb244a");
xhr.send(data);
you can make your service accept array of multipart file then you can send to it as much as you want of files to upload it and here is an exmaple
#RequestMapping(value="/multipleSave", method=RequestMethod.POST )
public #ResponseBody String multipleSave(#RequestParam("file") MultipartFile[] files){
String fileName = null;
String msg = "";
if (files != null && files.length >0) {
for(int i =0 ;i< files.length; i++){
try {
fileName = files[i].getOriginalFilename();
byte[] bytes = files[i].getBytes();
BufferedOutputStream buffStream =
new BufferedOutputStream(new FileOutputStream(new File("F:/cp/" + fileName)));
buffStream.write(bytes);
buffStream.close();
msg += "You have successfully uploaded " + fileName +"<br/>";
} catch (Exception e) {
return "You failed to upload " + fileName + ": " + e.getMessage() +"<br/>";
}
}
return msg;
} else {
return "Unable to upload. File is empty.";
}
}
}
and for the key part you can send all files with the same key
I am developing a System using Struts 1.x, Jsp Servlet and Pentaho(report generation).
Here when after generating report user can open and save that file as excel and that is working fine.
But problem occurs when a open a file, it creates file in our jboss temp folder that file is not deleted - that is the issue.
we are deleting file from code level and we figureout that after restating sever after first time it is deleting and other thing is when debugging it is deleting every time.
public Object process() throws RenderException, IOException {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
// properties for XSSF
File xmlFile = null;
File templateFile = null;
Writer xmlWriter = null;
boolean isXLSX = false;
timeStamp = Calendar.getInstance().getTimeInMillis();
try {
OutputType outputType = rendererAttrList.getOutputType();
Frame[] frameList = xmlDef.getShownFrames(renderDocs);
if (frameList != null) {
// ==============================================TPID#65448 code
// add========================================
boolean isPentahoExcel = false;
Frame t_CurrFrame = frameList[0];
if (t_CurrFrame != null) {
FrameType frameType = t_CurrFrame.getFrameType();
if (frameType == FrameType.FRAME_TYPE_EXTERNAL) {
isPentahoExcel = true;
}
}
// ==============================================TPID#65448 code end========================================
isXLSX = isXLSXOutput(frameList);
// native excel support and if the output is not supported by
// .xls, change the output to .xlsx
if (((outputType == OutputType.NATIVE_EXCEL2007) || ((outputType == OutputType.NATIVE_EXCEL97) && isXLSX))&&!isPentahoExcel)
{
workbook = new XSSFWorkbook();
rendererAttrList.setOutputType(OutputType.NATIVE_EXCEL2007);
xmlFile = File.createTempFile(getXmlDef().getName()
+ timeStamp, ".xml");
logger.info("XML File location :"
+ xmlFile.getAbsolutePath());
xmlWriter = new OutputStreamWriter(new FileOutputStream(
xmlFile), "UTF-8");
spreadSheetWriter = new SpreadsheetWriter(xmlWriter);
spreadSheetWriter.beginSheet();
} else {
workbook = new HSSFWorkbook();
}
dataFormat = workbook.createDataFormat();
sheet = workbook.createSheet("Report");
logger.debug("Start rendering the excel output in "
+ rendererAttrList.getOutputType() + " format ");
renderOutput();
logger.debug("Stop rendering the excel output ");
if (workbook instanceof HSSFWorkbook) {
// ==============================================TPID#65448 code add========================================
if (isPentahoExcel) {
renderExternalXLSX(t_CurrFrame,byteArrayOutputStream);
} else {
autoSizeColumn();
// write the excel to output
workbook.write(byteArrayOutputStream);
}
// ==============================================TPID#65448 code end========================================
} else {
// 1. generate data in XML format
spreadSheetWriter.endSheet();
// close the xml stream before we substitute in xlsx file
try {
if (xmlWriter != null)
xmlWriter.close();
xmlWriter = null;
} catch (Exception ex) {
logger.error("Error while closing xmlWriter for file "
+ xmlFile.getName());
}
// Step 2. create template from the excel workbook
String sheetRef = ((XSSFSheet) sheet).getPackagePart()
.getPartName().getName();
templateFile = createTemplate();
ByteArrayOutputStream xlsxOutput = new ByteArrayOutputStream();
// Step 3. Substitute the template entry with the generated
// data
substitute(templateFile, xmlFile, sheetRef.substring(1),
xlsxOutput);
// if the data is too large don't try to auto size the
// columns
// may result into out of memory exception
if (!isXLSX) {
// autosize the columns
InputStream inp = new ByteArrayInputStream(
xlsxOutput.toByteArray());
workbook = WorkbookFactory.create(inp);
sheet = workbook.getSheetAt(0);
autoSizeColumn();
if (xlsxOutput != null)
xlsxOutput.close();
byteArrayOutputStream = new ByteArrayOutputStream();
workbook.write(byteArrayOutputStream);
inp.close();
xlsxOutput.close();
} else {
byteArrayOutputStream = xlsxOutput;
}
}
}
} catch (Exception de) {
logger.error(de.getMessage(), de);
throw new RenderException(de.getMessage());
} finally {
try {
if (xmlWriter != null)
xmlWriter.close();
if (xmlFile != null)
xmlFile.delete();
if (templateFile != null){
templateFile.delete();
}
} catch (Exception ex) {
logger.error("Error while closing xmlWriter for file "
+ xmlFile.getName());
}
}
return byteArrayOutputStream;
}
Summary of my question - when Jboss restarting then first time and when debugging, temporary created file(temp directory) is deleting successfully .
but when it run normally it not deleting the file
but every time it is calling particular code level problem is why it doesn't perform.
templateFile.delete();
Thank you very much...
What happens when the delete method is called? You can log the output of the 'delete' method to see the result. It should be true or false.
Does it throw an exception? The delete method could throw a SecurityException indicating that you are denied access to delete the file.
In general, the first thing to do is try to understand why the file is not beeing deleted given the toolbox provided to you by this particular function.
Another approach could be to also call the deleteIfExists method instead. See here:
https://docs.oracle.com/javase/8/docs/api/java/nio/file/Files.html#deleteIfExists-java.nio.file.Path-
I want to save File to a client side. How it can be done ?
When i start server localy all is good Files are saved # needed place, when run on server then files are saved on server side :( . Because System.getProperty("user.home") are returning :/root .
User select File from system and wants to open it. Code example:
mylog.pl("Blob in use + stop counter:" + stop);
File file = new File(SU.userHome + "/" + fileName);
mylog.pl("File maked ! Path:" + file.getAbsolutePath());
in = blob.getBinaryStream();
out = new FileOutputStream(file);
byte[] buff = new byte[4096];
int len = 0;
while ((len = in.read(buff)) != -1) {
out.write(buff, 0, len);
}
try {
mylog.pl("Desktop Open!");
if (Desktop.isDesktopSupported())
{
Desktop.getDesktop().open(file);
}
else
{
mylog.pl("Desktop is not suported!");
//For other IS
DesktopApi.open(file);
}
}
catch (Exception e) {
mylog.pl("err # runtime" + e.getMessage());
}
Thanks ! Correct answers guaranteed !
//From server to client
final FileResource res = new FileResource(file);
FileDownloader fd = new FileDownloader(res);
p.open(res, "MyWindow", false);
file.delete();