downloading email body containing inline images in java - java

My issue goes as follows:
I have My code setup to read emails from a particular account. That part works perfectly.
the issue is with parsing the Email message. Separating attachments and email body(containing inline images).
My code goes like this:
Void readMessages(Folder folder){
Message[] messages = folder.getMessages();
// loading of message objects.
for (int messageNumber = 0; messageNumber < messages.length; messageNumber++) {
final Message currentMessage = messages[messageNumber];
logger.info("Handling the mail with subject " + currentMessage.getSubject());
logger.info("Content type for the current message is " + currentMessage.getContentType());
final String messageFileName = currentMessage.getFileName();
logger.info("File name for the message " + messageFileName + ". File name is blank "
+ StringUtils.isBlank(messageFileName));
Object messageContentObject = currentMessage.getContent();
if (messageContentObject instanceof Multipart) {
Multipart multipart = (Multipart) messageContentObject;
// downloading all attachments....
int attachmentCount = multipart.getCount();
logger.info("Number of attachments ");
for (int i = 0; i < attachmentCount; i++) {
Part part = (Part) multipart.getBodyPart(i);
downloadAttachment(part, folderPath.toString());
}
}
}
}
}
private void downloadAttachment(Part part, String folderPath) throws Exception {
String disPosition = part.getDisposition();
String fileName = part.getFileName();
String decodedText = null;
logger.info("Disposition type :: " + disPosition);
logger.info("Attached File Name :: " + fileName);
if (disPosition != null && disPosition.equalsIgnoreCase(Part.ATTACHMENT)) {
logger.info("DisPosition is ATTACHMENT type.");
File file = new File(folderPath + File.separator + decodedText);
file.getParentFile().mkdirs();
saveEmailAttachment(file, part);
} else if (fileName != null && disPosition == null) {
logger.info("DisPosition is Null type but file name is valid. Possibly inline attchment");
File file = new File(folderPath + File.separator + decodedText);
file.getParentFile().mkdirs();
saveEmailAttachment(file, part);
} else if (fileName == null && disPosition == null) {
logger.info("DisPosition is Null type but file name is null. It is email body.");
File file = new File(folderPath + File.separator + "mail.html");
file.getParentFile().mkdirs();
saveEmailAttachment(file, part);
}
}
protected int saveEmailAttachment(File saveFile, Part part) throws Exception {
BufferedOutputStream bos = null;
InputStream is = null;
int ret = 0, count = 0;
try {
bos = new BufferedOutputStream(new FileOutputStream(saveFile));
part.writeTo(new FileOutputStream(saveFile));
} finally {
try {
if (bos != null) {
bos.close();
}
if (is != null) {
is.close();
}
} catch (IOException ioe) {
logger.error("Error while closing the stream.", ioe);
}
}
return count;
}
The problem i get is when i run this code, i get an HTML file but the inline images is replaced by a sign for error image which indicates the image with no source.
Please help me out with. Let me know if any more info is required.
I also tried saving the body as an .eml file by changing:
File file = new File(folderPath + File.separator + "mail.html");
to
File file = new File(folderPath + File.separator + "mail.eml");
BUt i got the same results.

I wrote below code to convert email body text to pdf including inline images.
in code i replaced the image code(ex: cid:image001.jpg#01D17AAA.1EA2A6A0) with download image path. I am constructing the "hashmap" for image key and download path while downloading the image.
HTMLWorker htmlWorker = new HTMLWorker(document);
if(bodyStr!=null)
{
//find inline images
inlineImages=downloadInLineImage(mostRecentMatch, dynamicOutputDirectory);
if(inlineImages!=null)
{
for (Map.Entry<String, String> entry : inlineImages.entrySet()) {
//System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());
bodyStr=bodyStr.replaceAll("cid:"+entry.getKey() , entry.getValue());
}
}
htmlWorker.parse(new StringReader(bodyStr));
}
Download Inline image with passing Item.
private HashMap<String,String> downloadInLineImage(Item item, String dynamicOutputDirectory)
throws Exception, ServiceLocalException {
//create output directory if not present
//bind the item to a new email message. if you do not bind, then the getHasAttachments() function will fail
EmailMessage mostRecentMatch = (EmailMessage)item;
String from = mostRecentMatch.getFrom().getAddress();
String user =StringUtils.substringBefore(from, "#");
AttachmentCollection collection=item.getAttachments();
HashMap<String,String> inlineFiles=new HashMap<String,String>();
if(collection.getCount()>0)
{
for (Attachment attachment : collection.getItems()) {
if(attachment.getIsInline())
{
FileAttachment currentFile = (FileAttachment) attachment;
String filePath=dynamicOutputDirectory+"/"+user+currentFile.getName();
File file=new File(filePath);
FileOutputStream fio=new FileOutputStream(file);
currentFile.load(fio);
inlineFiles.put(currentFile.getContentId(), filePath);
fio.close();
}
}
}

References to inlined images are replaced by cid: URNs like <img src="cid:SOMEID">, because there are no filenames in an email. SOMEID refers to the Content-ID of the Multipart "objects".
In order to get it work, you have to store the multipart attachments to files (e.g., temporary names) and replace the cid URNs by the real file names.

Related

How to fix "cannot access file because it is being used by another process"

I'm running a program that will call a code based on a condition.
if (charCount >= 152) {
new InformixToPDF().createPdflandscape( DESTINATION +
"\\" + new_file_name + "_" + df.format(new Date()) + ".pdf",source);
}
//function to call for portrait conversion
else {
new InformixToPDF().createPdfportrait( DESTINATION +
"\\" + new_file_name + "_" + df.format(new Date()) + ".pdf",source);
}
Here the code that's called if else condition are met.
public void createPdfportrait(String dest,String source) throws DocumentException, IOException {
File myfile = new File(source);
Document document = new Document(PageSize.A4);
document.setMargins (20, 0, 50, 80);
PdfWriter.getInstance(document, new FileOutputStream(dest));
document.open();
br = new BufferedReader(new FileReader(source));
String line;
Paragraph p;
//PDF font configuration
Font normal = new Font(FontFamily.COURIER, 7);
Font bold = new Font(FontFamily.COURIER, 7, Font.BOLD);
//add page into PDF
boolean title = true;
while ((line = br.readLine()) != null) {
p = new Paragraph(line.length() == 0 ? " ": line, title ? bold : normal);
document.add(p);
}
document.close();
System.out.println("Informix4gl report file " + source + " has been converted to PDF");
Path sourcePath = Paths.get(source);
Path destinationPath = Paths.get(MOVE);
try {
Files.move(sourcePath, destinationPath,
StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
e.printStackTrace();
}
}
After conversion has been done the current file. it need to be move to another folder using this code where "source" is the current file and "MOVE" is destination folder.
Path sourcePath = Paths.get(source);
Path destinationPath = Paths.get(MOVE);
try {
Files.move(sourcePath, destinationPath,
StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
e.printStackTrace();
}
The codes is executed and pdf is created successfully but error "java.nio.file.FileSystemException: O:\xx\yy\zz\test -> O:\xx\yy\zz\FOLDER C: The process cannot access the file because it is being used by another process." appear.
How do I fix this and what change should I make to the code to avoid this error?
I know these question was asked a lot but none of that fixed my problem. However I may have missed some.

java.io.FileNotFoundException: C:\Users\user\AppData\Local\Temp (Access is denied)

When I upload files to local system's temp directory from Mozilla Browser I get Access denied error. But if I do the same thing from Eclipse Browser I dont see any error, means it is uploading without any error:
Code:
for (Part part : request.getParts()) {
fileName = getFileName(part);
part.write(System.getProperty("java.io.tmpdir") + fileName);
}
private String getFileName(Part part) {
String contentDisp = part.getHeader("content-disposition");
System.out.println("content-disposition header= "+contentDisp);
String[] tokens = contentDisp.split(";");
for (String token : tokens) {
if (token.trim().startsWith("filename")) {
return token.substring(token.indexOf("=") + 2, token.length()-1);
}
}
return "";
Error:
java.io.IOException: java.io.FileNotFoundException: C:\Users\user\AppData\Local\Temp (Access is denied)
Allan, this is the code:
final String path = System.getProperty("java.io.tmpdir");
OutputStream out = null;
InputStream filecontent = null;
final PrintWriter writer = response.getWriter();
try {
for (Part part : request.getParts()) {
String fileName = getFileName(part);
out = new FileOutputStream(new File(path , fileName));
filecontent = part.getInputStream();
int read = 0;
final byte[] bytes = new byte[1024];
while ((read = filecontent.read(bytes)) != -1) {
out.write(bytes, 0, read);
}
File UploadedFile = new File(path + File.separator + fileName);
UploadedFile.delete();
}
} catch (FileNotFoundException fne) {
writer.println("You either did not specify a file to upload or are "
+ "trying to upload a file to a protected or nonexistent "
+ "location.");
} finally {
if (out != null) {
out.close();
}
if (filecontent != null) {
filecontent.close();
}
if (writer != null) {
writer.close();
}
}
See this example, when create the file use two parameter as the example:
File scratchFile = new File(System.getProperty("java.io.tmpdir"), "filename.tmp");
Example:
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
// Create path components to save the file
final String path = System.getProperty("java.io.tmpdir");
final Part filePart = request.getPart("file");
final String fileName = getFileName(filePart);
OutputStream out = null;
InputStream filecontent = null;
final PrintWriter writer = response.getWriter();
try {
//File Temp here with two parameters
out = new FileOutputStream(new File(path , "filename.tmp"));
filecontent = filePart.getInputStream();
int read = 0;
final byte[] bytes = new byte[1024];
while ((read = filecontent.read(bytes)) != -1) {
out.write(bytes, 0, read);
}
writer.println("New file " + fileName + " created at " + path);
} catch (FileNotFoundException fne) {
writer.println("You either did not specify a file to upload or are "
+ "trying to upload a file to a protected or nonexistent "
+ "location.");
writer.println("<br/> ERROR: " + fne.getMessage());
} finally {
if (out != null) {
out.close();
}
if (filecontent != null) {
filecontent.close();
}
if (writer != null) {
writer.close();
}
}
}
And your method:
private String getFileName(final Part part) {
final String partHeader = part.getHeader("content-disposition");
LOGGER.log(Level.INFO, "Part Header = {0}", partHeader);
for (String content : part.getHeader("content-disposition").split(";")) {
if (content.trim().startsWith("filename")) {
return content.substring(content.indexOf('=') + 1).trim().replace("\"", "");
}
}
return null;
}
References:
Permission
Upload Method
In case of a web application, the Webcontainer might have set some SecurityManager (https://docs.oracle.com/javase/8/docs/api/java/lang/SecurityManager.html) to block write access to the local file system.
Check if this has been the case...
Same problem I was facing few minutes ago.
Your code won't work for file upload with other request parameter together.
when you're calling getParts() it takes other parameters also as parts.
Now in case of file taken as part content-dipsosition header has
form-data; name="<file-parameter-name>"; filename="<filename>"
A thing to be noted <filename> may be different if submitted from
different browser. Try to submit it from eclipse's in built browser.
Try to print and see content-disposition header by
System.out.println(part.getHeader("content-disposition"));
In case of your loop runs for other parameters taken as part, content-disposition has
form-data; name=""
Now see there is nothing like filename="", so your function to get filename returns null.
Now you calls part.write() but inside only path is passed not filename as function you called to get filename returns null. So you get exception even thought it actually uploads file.
After getting filename put a condition
if(filename.equals("")){continue;}
But that's also not a good solution as loop iterate for no reason for other parameter.

EWS Java API get Attachment

I have some issue in getting some attachment using ews java API 1.3 SNAPSHOT, i want to get Attachment in my email, here my code :
try {
ExchangeService service;
service.setUrl(new URI("https://" + myserver + "/ews/Exchange.asmx"));
ExchangeCredentials credentials = new WebCredentials(username, password);
service.setCredentials(credentials);
ItemView view = new ItemView(Integer.MAX_VALUE);
view.getOrderBy().add(ItemSchema.DateTimeReceived, SortDirection.Ascending);
Folder folder = Folder.bind(service, WellKnownFolderName.Inbox);
FindItemsResults<Item> results = service.findItems(folder.getId(),view);
service.loadPropertiesForItems(results, new PropertySet(BasePropertySet.FirstClassProperties, EmailMessageSchema.Attachments));
for (Item item : results) {
Item itm = Item.bind(service, item.getId(), new PropertySet(BasePropertySet.FirstClassProperties, EmailMessageSchema.Attachments));
EmailMessage emailMessage = EmailMessage.bind(service, itm.getId(), new PropertySet(BasePropertySet.FirstClassProperties, EmailMessageSchema.Attachments));
if (emailMessage.getHasAttachments()) {
for (Attachment attachment : emailMessage.getAttachments()) {
String FileExtension = getFileExtension(attachment.getName());
File TempFile = File.createTempFile(attachment.getName(), FileExtension);
attachment.load(TempFile.getAbsolutePath());
}
}
}
} catch (Exception e) {
logger.error("Error ", e.getMessage());
}
My issue is it can get another email that has no attachment and always skip email that has an attachment, the example is like this,
In my inbox i have this email list
from: a#gmail.com (has attachment)
from: b#mycompany.com (no attachment)
from: c#hiscompany.com (has attachment)
from: d#mycompany.com (no attachment)
And when i run my code, it always get email that has no attachment, like this:
from: b#mycompany.com (no attachment)
from: d#mycompany.com (no attachment)
and skip the other email that has attachment, i have no idea how can this happen. Can someone help me please?
HashMap<String, HashMap<String, String>> attachments = new HashMap<String, HashMap<String, String>>();
if (emailMessage.getHasAttachments() || emailMessage.getAttachments().getItems().size() > 0) {
//get all the attachments
AttachmentCollection attachmentsCol = emailMessage.getAttachments();
log.info("File Count: " +attachmentsCol.getCount());
//loop over the attachments
for (int i = 0; i < attachmentsCol.getCount(); i++) {
Attachment attachment = attachmentsCol.getPropertyAtIndex(i);
//log.debug("Starting to process attachment "+ attachment.getName());
//FileAttachment - Represents a file that is attached to an email item
if (attachment instanceof FileAttachment || attachment.getIsInline()) {
attachments.putAll(extractFileAttachments(attachment, properties));
} else if (attachment instanceof ItemAttachment) { //ItemAttachment - Represents an Exchange item that is attached to another Exchange item.
attachments.putAll(extractItemAttachments(service, attachment, properties, appendedBody));
}
}
}
} else {
log.debug("Email message does not have any attachments.");
}
//Extract File Attachments
try {
FileAttachment fileAttachment = (FileAttachment) attachment;
// if we don't call this, the Content property may be null.
fileAttachment.load();
//extract the attachment content, it's not base64 encoded.
attachmentContent = fileAttachment.getContent();
if (attachmentContent != null && attachmentContent.length > 0) {
//check the size
int attachmentSize = attachmentContent.length;
//check if the attachment is valid
ValidateEmail.validateAttachment(fileAttachment, properties,
emailIdentifier, attachmentSize);
fileAttachments.put(UtilConstants.ATTACHMENT_SIZE, String.valueOf(attachmentSize));
//get attachment name
String fileName = fileAttachment.getName();
fileAttachments.put(UtilConstants.ATTACHMENT_NAME, fileName);
String mimeType = fileAttachment.getContentType();
fileAttachments.put(UtilConstants.ATTACHMENT_MIME_TYPE, mimeType);
log.info("File Name: " + fileName + " File Size: " + attachmentSize);
if (attachmentContent != null && attachmentContent.length > 0) {
//convert the content to base64 encoded string and add to the collection.
String base64Encoded = UtilFunctions.encodeToBase64(attachmentContent);
fileAttachments.put(UtilConstants.ATTACHMENT_CONTENT, base64Encoded);
}
//Extract Item Attachment
try {
ItemAttachment itemAttachment = (ItemAttachment) attachment;
PropertySet propertySet = new PropertySet(
BasePropertySet.FirstClassProperties, ItemSchema.Attachments,
ItemSchema.Body, ItemSchema.Id, ItemSchema.DateTimeReceived,
EmailMessageSchema.DateTimeReceived, EmailMessageSchema.Body);
itemAttachment.load();
propertySet.setRequestedBodyType(BodyType.Text);
Item item = itemAttachment.getItem();
eBody = appendItemBody(item, appendedBody.get(UtilConstants.BODY_CONTENT));
appendedBody.put(UtilConstants.BODY_CONTENT, eBody);
/*
* We need to check if Item attachment has further more
* attachments like .msg attachment, which is an outlook email
* as attachment. Yes, we can attach an email chain as
* attachment and that email chain can have multiple
* attachments.
*/
AttachmentCollection childAttachments = item.getAttachments();
//check if not empty collection. move on
if (childAttachments != null && !childAttachments.getItems().isEmpty() && childAttachments.getCount() > 0) {
for (Attachment childAttachment : childAttachments) {
if (childAttachment instanceof FileAttachment) {
itemAttachments.putAll(extractFileAttachments(childAttachment, properties, emailIdentifier));
} else if (childAttachment instanceof ItemAttachment) {
itemAttachments = extractItemAttachments(service, childAttachment, properties, appendedBody, emailIdentifier);
}
}
}
} catch (Exception e) {
throw new Exception("Exception while extracting Item Attachments: " + e.getMessage());
}

java mail polling read inline or embedded images (smileys) from the mail

I am new in java mail polling and i have create one type of conversation application in this if user send mail to each other then i read that from them mail and post as new message in conversation.
now issue is that, what to do if there is smileys, inline or embedded images. for example in gmail mail we can send smileys also now how read that smile and post on to the over page. please give me some proper solution for this.
I have found the solution to download the inline images + icons from the mail.
private String getAttachments(Message message, HttpServletRequest request) throws MessagingException, IOException {
String contentType = message.getContentType();
String attachFiles="";
if (contentType.contains("multipart")) {
// content may contain attachments
Multipart multiPart = (Multipart) message.getContent();
int numberOfParts = multiPart.getCount();
for (int partCount = 0; partCount < numberOfParts; partCount++) {
MimeBodyPart part = (MimeBodyPart) multiPart.getBodyPart(partCount);
String disposition =part.getDisposition();
String file=part.getFileName();
//External attachments
if (disposition != null && Part.ATTACHMENT.equalsIgnoreCase(disposition)) {
// this part is attachment
String fileName = new Date().getTime()+ "_"+ part.getFileName().replaceAll("[^a-zA-Z0-9\\._]+", "_"); //To make attachment name uniq we are adding current datatime before name.
attachFiles += fileName + ","; //concrete all attachment's name with comma separated.
part.saveFile(new File(request
.getSession()
.getServletContext()
.getRealPath(
"/WEB-INF/attechments/"
+ fileName))); //To save the attachment file at specific location.
// LOG.info("\n\t Path :- " +request.getSession().getServletContext().getRealPath("/WEB-INF/attechments/" + fileName));
}
//Inline Attachments
else if (disposition != null && Part.INLINE.equalsIgnoreCase(disposition)) {
// this part is attachment
String fileName = new Date().getTime()+ "_"+ part.getFileName().replaceAll("[^a-zA-Z0-9\\._]+", "_"); //To make attachment name uniq we are adding current datatime before name.
// attachFiles += fileName + ","; //concrete all attachment's name with comma separated.
part.saveFile(new File(request
.getSession()
.getServletContext()
.getRealPath(
"/WEB-INF/attechments/"
+ fileName))); //To save the attachment file at specific location.
// LOG.info("\n\t Path :- " +request.getSession().getServletContext().getRealPath("/WEB-INF/attechments/" + fileName));
}
//Inline icons and smileys
else if(file != null && disposition==null)
{
String fileName = new Date().getTime()+ "_"+ part.getFileName().replaceAll("[^a-zA-Z0-9\\._]+", "_");
// attachFiles += fileName + ","; //concrete all attachment's name with comma separated.
part.saveFile(new File(request
.getSession()
.getServletContext()
.getRealPath(
"/WEB-INF/attechments/"
+ fileName)));
}
}
}
if (attachFiles.length() > 1) {
attachFiles = attachFiles.substring(0, attachFiles.length() - 1);
}
return attachFiles;
}

Best way to save email, including images and HTML data, using Java Mail API?

I'm looking for the best way to save an email body which includes inline images and HTML content. I want to Retain everything the mail contains.
My ultimate Goal is to save the complete email body into a PDF
If there is a direct way to write email body into PDF ?
if not what would be the best format to save the email ?
I can convert HTML, DOC etc to PDF using some other available API.
private void downloadAttachment(Part part, String folderPath) throws Exception {
String disPosition = part.getDisposition();
String fileName = part.getFileName();
String decodedText = null;
logger.info("Disposition type :: " + disPosition);
logger.info("Attached File Name :: " + fileName);
if (disPosition != null && disPosition.equalsIgnoreCase(Part.ATTACHMENT)) {
logger.info("DisPosition is ATTACHMENT type.");
File file = new File(folderPath + File.separator + decodedText);
file.getParentFile().mkdirs();
saveEmailAttachment(file, part);
} else if (fileName != null && disPosition == null) {
logger.info("DisPosition is Null type but file name is valid. Possibly inline attchment");
File file = new File(folderPath + File.separator + decodedText);
file.getParentFile().mkdirs();
saveEmailAttachment(file, part);
} else if (fileName == null && disPosition == null) {
logger.info("DisPosition is Null type but file name is null. It is email body.");
File file = new File(folderPath + File.separator + "mail.html");
file.getParentFile().mkdirs();
saveEmailAttachment(file, part);
}
}
protected int saveEmailAttachment(File saveFile, Part part) throws Exception {
BufferedOutputStream bos = null;
InputStream is = null;
int ret = 0, count = 0;
try {
bos = new BufferedOutputStream(new FileOutputStream(saveFile));
part.writeTo(new FileOutputStream(saveFile));
} finally {
try {
if (bos != null) {
bos.close();
}
if (is != null) {
is.close();
}
} catch (IOException ioe) {
logger.error("Error while closing the stream.", ioe);
}
}
return count;
}
Please suggest. Thank you!
Save it in its natural state, as a MimeMessage.
JavaMail MimeMessages can be streamed to text, since that's how they arrive in mail. For example, MimeMessage.writeTo saves the message out as text. Similarly, MimeMessage.parse reads it back in. One in a MimeMessage, you can get the text, the attachments, etc. quite easily.
You could also stream it out as a serialized Java object, but, frankly, I wouldn't. The text representation is much more useful.

Categories