Extracting PST file containing mail as an attachment of PSTMessage - java

I'm trying to extract PST files using java-libpst-0.8.1 , following
https://code.google.com/p/java-libpst/
In my sample pst file, there are several mails. In one of the mail of that pst file, the attachment is also a mail. While parsing that PSTMessage, it's not able to fetch even, attachment's name. Please find the sample code.
PSTMessage email;
PSTAttachment attach;
email = (PSTMessage) folder.getNextChild();
while (email != null) {
try {
numberOfAttachments = email.getNumberOfAttachments();
if (numberOfAttachments > 0) {
for (int x = 0; x < numberOfAttachments; x++) {
attach = email.getAttachment(x);
try {
attachmentName = attach.getLongFilename();
Though the program is giving the exact count of the mail's attachments. But it's not able to provide, the attached mail's name or extracting it's content. Can anyone suggest a way what should I do?

Finally, I'm able to read the mail which is an attachment of a mail. There is a method getEmbeddedPSTMessage() in PSTAttachment class. First I need to check whether it's a normal attachment or a mail. For that we need to refer getAttachMethod(). If it returns 5 it's an embedded message. For details, please check out the documentation of PSTAttachment.
if (attach.getAttachMethod() == 5) {
PSTMessage attachEmail = attach.getEmbeddedPSTMessage();
}

Have you tried to convert the EmbeddedPSTMessage into actual .msg format?
I am using the the library to read the pst file and the second process is I am converting the PSTMessage into javax.mail.internet.MimeMessage and save it as .eml.
The problem I have now is that whenever the attachment is embedded message (.msg format), it is getting converted to .dat extension.
Would you know how to convert the EmbeddedPSTMessage and attach it as the original msg format?
Im really desperate right now.
Below are the codes snippet:
// saving as .eml
MimeMessage mimeMessage = convertToMimeMessage(email);
fileName = getRidOfIllegalFileNameCharacters(email.getSubject());
File emlFile = new File("C:\\eml\\" + fileName + ".eml");
emlFile.createNewFile();
mimeMessage.writeTo(new FileOutputStream(emlFile));
private static MimeMessage convertToMimeMessage(PSTMessage email) throws MessagingException, IOException, PSTException {
Properties p = System.getProperties();
Session session = Session.getInstance(p);
MimeMessage mimeMessage = new MimeMessage(session);
//attachment part
MimeMultipart rootMultipart = new MimeMultipart();
for (int i = 0; i < email.getNumberOfAttachments(); i++) {
PSTAttachment attachment = email.getAttachment(i);
if (attachment != null && attachment.getFileInputStream() != null) {
MimeBodyPart attachmentBodyPart = new MimeBodyPart();
if (attachment.getMimeTag() != null && attachment.getMimeTag().length() > 0) {
DataSource source = new ByteArrayDataSource(attachment.getFileInputStream(), attachment.getMimeTag());
attachmentBodyPart.setDataHandler(new DataHandler(source));
} else {
DataSource source = new ByteArrayDataSource(attachment.getFileInputStream(), "application/octet-stream");
attachmentBodyPart.setDataHandler(new DataHandler(source));
}
attachmentBodyPart.setContentID(attachment.getContentId());
String fileName = "";
if (attachment.getLongFilename() != null && attachment.getLongFilename().length() > 0) {
fileName = attachment.getLongFilename();
} else if (attachment.getDisplayName() != null && attachment.getDisplayName().length() > 0) {
fileName = attachment.getDisplayName();
} else if (attachment.getFilename() != null && attachment.getFilename().length() > 0) {
fileName = attachment.getFilename();
}
attachmentBodyPart.setFileName(fileName);
rootMultipart.addBodyPart(attachmentBodyPart);
}
}
mimeMessage.setContent(rootMultipart);
return mimeMessage;

JPST exports embedded messages as attachments in the original .msg file format. As I remember they have method in the Attachment object to identify if attachment is embedded message.
JPST is another library, not free one you use, but worth to try.
Example:
for (Attachment attachment : message.getAttachments()) {
Message embeddedMessage = attachment.getEmbeddedMessage();
if (embeddedMessage != null) {
embeddedMessage.setEmbedded(false); //Important
embeddedMessage.save("e:\\testfolder\\" +
getFileName(attachment.getDisplayName()) + ".msg");
} else {
attachment.save("e:\\testfolder\\" + attachment.getFileName());
}
}

Related

Why iterate over the parts in a multipart email in javamail?

I was looking at that javamail faqs, I was looking at this snippet which is supposed to extract the body of the email:
private boolean textIsHtml = false;
/**
* Return the primary text content of the message.
*/
private String getText(Part p) throws
MessagingException, IOException {
if (p.isMimeType("text/*")) {
String s = (String)p.getContent();
textIsHtml = p.isMimeType("text/html");
return s;
}
if (p.isMimeType("multipart/alternative")) {
// prefer html text over plain text
Multipart mp = (Multipart)p.getContent();
String text = null;
for (int i = 0; i < mp.getCount(); i++) {
Part bp = mp.getBodyPart(i);
if (bp.isMimeType("text/plain")) {
if (text == null)
text = getText(bp);
continue;
} else if (bp.isMimeType("text/html")) {
String s = getText(bp);
if (s != null)
return s;
} else {
return getText(bp);
}
}
return text;
} else if (p.isMimeType("multipart/*")) {
Multipart mp = (Multipart)p.getContent();
for (int i = 0; i < mp.getCount(); i++) {
String s = getText(mp.getBodyPart(i));
if (s != null)
return s;
}
}
return null;
}
Now the code can be refactored to the following version which is basically less lines of code:
private static String getText(Part message) {
String text = null;
try {
if (message.isMimeType("text/*")) {
text = (String) message.getContent();
}
if (message.isMimeType("multipart/alternative") || message.isMimeType("multipart/*")) {
Multipart multiPart = (Multipart) message.getContent();
Part bodyPart = multiPart.getBodyPart(multiPart.getCount() - 1);
text = getText(bodyPart);
}
} catch (Exception e) {
logger.error(e.getMessage());
}
return text;
}
My question is, why the old code looping through the parts for both multipart/alternative and multipart/* messages? Am I missing something here?
Update:
Just saw Jon's comment, I have a further question, is there any scenario where my version of the code will break?
Basically there are many Multipart types and they all need to handled uniquely:
Mixed Subtype
The "mixed" subtype of "multipart" is intended for use when the body
parts are independent and need to be bundled in a particular order.
Any "multipart" subtypes that an implementation does not recognize
must be treated as being of subtype "mixed".
Alternative Subtype
The "multipart/alternative" type is syntactically identical to
"multipart/mixed", but the semantics are different. In particular,
each of the body parts is an "alternative" version of the same
information.
Systems should recognize that the content of the various parts are interchangeable. Systems should choose the "best" type based on the local environment and references, in some cases even through user interaction. As with "multipart/mixed", the order of body parts is significant. In this case, the alternatives appear in an order of increasing faithfulness to the original content.
In general, the best choice is the LAST part of a type supported by the recipient system's local environment.
"Multipart/alternative" may be used, for example, to send a message
in a fancy text format in such a way that it can easily be displayed
anywhere:
From: Nathaniel Borenstein <nsb#bellcore.com>
To: Ned Freed <ned#innosoft.com>
Date: Mon, 22 Mar 1993 09:41:09 -0800 (PST)
Subject: Formatted text mail
MIME-Version: 1.0
Content-Type: multipart/alternative; boundary=boundary42
--boundary42
Content-Type: text/plain; charset=us-ascii
... plain text version of message goes here ...
--boundary42
Content-Type: text/enriched
... RFC 1896 text/enriched version of same message
goes here ...
--boundary42
Content-Type: application/x-whatever
... fanciest version of same message goes here ...
--boundary42--
In this example, users whose mail systems understood the
"application/x-whatever" format would see only the fancy version,
while other users would see only the enriched or plain text version,
depending on the capabilities of their system.
Your code won't "work" (whatever that means to you) with a multipart/mixed message where the last attachment is of type text/*. Yes, attachments can be of type text/*.

Incorrect content in mail for HTML data

I am trying to send the mail using JavaMailSender which include the html content but instead of the rendered html in the email i am getting the html code itself in the mail i.e
Method used to send email
public void sendMimeMessage(String from, String to, String subject, String messageBody, String... cc) {
MimeMessage message = mailSender.createMimeMessage()
try {
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setFrom(from)
helper.setSentDate(new Date())
helper.setSubject(subject)
helper.setText(messageBody, true)
helper.setTo(to)
helper.setCc(cc)
mailSender.send(message)
log.debug("Email successfully sent to <${to}> with cc <${cc}> and with subject <${subject}> and Email body: ${messageBody}")
} catch (Exception exception) {
exception.printStackTrace()
log.error("Email to <${to}> with subject <${subject}> could not be sent due to: ", exception)
}
}
Any help would be appreciated.
This might help you.
You can use Apache velicity, or can see my Answer.
Sample code:
JavaMailSenderImpl sender = new JavaMailSenderImpl();
sender.setHost("mail.host.com");
MimeMessage message = sender.createMimeMessage();
// use the true flag to indicate you need a multipart message
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setTo("test#host.com");
// use the true flag to indicate the text included is HTML
helper.setText("<html><body><img src='cid:identifier1234'></body></html>", true);
// let's include the infamous windows Sample file (this time copied to c:/)
FileSystemResource res = new FileSystemResource(new File("c:/Sample.jpg"));
helper.addInline("identifier1234", res);
sender.send(message);
This worked for me.
Step 1. Construct the messageBody as follows:
Let suppose you need a HTML content in mail like shown below
**SERIAL NO PROCESS_INSTANCE_ID USONUMBER**
1 TSV00876 N89876
2 LMNV0083 V89876
Let suppose you have list from where you are going to populate above columns.
List<Report> list = xyzService.getReport(); **//returns list of Report**
StringBuilder buf = new StringBuilder();
buf.append("<!doctype html>\n");
buf.append("<html lang='en'>\n");
buf.append("<head>\n");
buf.append("<meta charset='utf-8'>\n");
buf.append("<title>Report</title>\n");
buf.append("</head>\n");
buf.append("<body>" +
"<table border ='1'>" + "<tr>" +
"<th>SERIAL NO</th>" +
"<th>PROCESS_INSTANCE_ID</th>" +
"<th>USONUMBER</th>"+
"</tr>\n");
for (int i = 0; i < list.size(); i++) {
buf.append("<tr><td>").
append(list.get(i)).getSerialNo().append("</td><td>").
append(list.get(i).getProcessInstanceId()).append("</td><td>").
append(list.get(i).getUsoNumber()).append("</td><td>").
append("</td></tr>\n");
}
buf.append("</table>\n" +
"</body>\n" +
"</html>");
String messageBody = buf.toString();
Step 2. pass this string messageBody in your method sendMimeMessage() and set
MimeMessageHelper as shown below.
MimeMessage message = mailSender.createMimeMessage()
MimeMessageHelper helper = new MimeMessageHelper(message,MimeMessageHelper.MULTIPART_MODE_MIXED_RELATED,StandardCharsets.UTF_8.name());
helper.setText(messageBody, true);

How to get filename of all attachements of email?

I am trying to get the filename of all the attachements of emails using java and imap.My code is:
MimeMessage msg = (MimeMessage) messages[i];
String fileName = msg.getFileName();
System.out.println("The file name of this attachment is " + fileName);
but it prints null always even if email contain attachment..I have seen different codes on SO but none worked...and I don't know what to do if attachment is more than one .
PS:I only want to get the filename and don't want to download attachments.
First, to determine if a message may contain attachments using the following code:
// suppose 'message' is an object of type Message
String contentType = message.getContentType();
if (contentType.contains("multipart")) {
// this message may contain attachment
}
Then we must iterate through each part in the multipart to identify which part contains the attachment, as follows:
Multipart multiPart = (Multipart) message.getContent();
for (int i = 0; i < multiPart.getCount(); i++) {
MimeBodyPart part = (MimeBodyPart) multiPart.getBodyPart(i);
if (Part.ATTACHMENT.equalsIgnoreCase(part.getDisposition())) {
// this part is attachment
// code to save attachment...
}
}
And to save the file, you could do:
part.saveFile("D:/Attachment/" + part.getFileName());
Source
there is an easier way with apache commons mail:
final MimeMessageParser mimeParser = new MimeMessageParser(mimeMessage).parse();
final List<DataSource> attachmentList = mimeParser.getAttachmentList();
for (DataSource dataSource: attachmentList) {
final String fileName = dataSource.getName();
System.out.println("filename: " + fileName);
}
I was facing the same issue when the email contained another email as an attachment. The content-disposition of such an attachment does not contain fileName.
String contentType = message.getContentType();
List<String> attachmentFiles = new ArrayList<String>();
if(contentType.contains("multipart"))
{
Multipart multiPart = (Multipart)message.getContent();
int numberOfParts = multiPart.getCount();
for(int partCount = 0; partCount < numberOfParts; partCount++)
{
MimeBodyPart part = (MimeBodyPart)multiPart.getBodyPart(partCount);
if(Part.ATTACHMENT.equalsIgnoreCase(part.getDisposition())) {
String fileName = part.getFileName();
String extension = FilenameUtils.getExtension(fileName);
//If the attachment is an email, fileName will be null.
if ("message/rfc822".equalsIgnoreCase(part.getContentType())) {
MimeMessage tempMessage = new MimeMessage(null, part.getInputStream());
fileName = tempMessage.getSubject()+".eml"; //all the email attachments will be converted to .eml format.
extension = "eml";
}
File tempEmailFile = File.createTempFile(messageId + "_" + partCount , "." + extension);
part.saveFile(tempEmailFile);
attachmentFiles.add(fileName);
attachmentFiles.add(tempEmailFile.getAbsolutePath());
}
}
}
Reference: javamail also extract attachments of encapsulated message Content-Type: message/rfc822

Javamail Parsing Email Body with 7BIT Content-Transfer-Encoding

I've been implementing an feature to read email file. If the file have attachment, return attachment name.
Now I'm using Javamail library to parse email file. Here is my code.
public static void parse(File file) throws Exception {
InputStream source = new FileInputStream(file);
MimeMessage message = new MimeMessage(null, source);
Multipart multipart = (Multipart) message.getContent();
for (int i = 0; i < multipart.getCount(); i++) {
BodyPart bodyPart = multipart.getBodyPart(i);
String disposition = bodyPart.getDisposition();
if (disposition != null
&& disposition.equalsIgnoreCase(Part.ATTACHMENT)) {
System.out.println("FileName:"
+ MimeUtility.decodeText(bodyPart.getFileName()));
}
}
}
It works fine but when email file have 7bit Content-Transfer-Encoding, bodyPart.getFileName() make NullPointerException.
Is there any way to get attachement name when email is 7bit Content-Transfer-Encoding?
Sorry for my poor English.
Edited: Here is some info about my test file.
(X-Mailer: Mew version 2.2 on Emacs 21.3 / Mule 5.0 (SAKAKI)); (Mime-Version:1.0):(Content-Type: Multipart/Mixed); (Content-Transfer-Encoding: 7bit)
If my answer does not work, show the stack trace.
Use a Session, as that probably is the only thing being null.
Properties properties = new Properties();
Session session = Session.getDefaultInstance(properties);
MimeMessage message = new MimeMessage(session, source);
Not all attachments have a filename. You need to handle that case.
And you don't need to decode the filename.
You can handle the case of "attachments not having a name" in this way:
String fileName = (bodyPart.getFileName() == null) ? "your_filename"
: bodyPart.getFileName();

Reading mails sent from GMail

I am using JavaMail to read mail in my Android app. I have tried to cover all combinations i.e Mail sent/received on/from Custom Server/Gmail ID/Live ID.
The problem occurs with SOME of the mails sent from GMail WITH Attachment. I am able to receive the attachment, but the content returns javax.mail.internet.MimeMultipart#44f2e698
Here's the code used to receive and read messages:
Properties props = System.getProperties();
props.setProperty("mail.store.protocol", "imap");
try {
/* Create the session and get the store for read the mail. */
Session session = Session.getInstance(props, null);
Store store = session.getStore("imaps");
store.connect("imap.gmail.com", Username, Password);
/* Mention the folder name which you want to read. */
Folder inbox = store.getFolder("INBOX");
System.out.println("No of Unread Messages : " + inbox.getUnreadMessageCount());
/* Open the inbox using store. */
inbox.open(Folder.READ_ONLY);
Message messages[] = inbox.getMessages();
Log.d("Inbox", "Message Count: "+inbox.getMessageCount());
for (int i = messages.length - 1 ; i > 0; --i) {
Log.i("ContentType", "ContentType: "+messages[i].getContentType());
Object msgContent = messages[i].getContent();
String content = "";
/* Check if content is pure text/html or in parts */
if (msgContent instanceof Multipart) {
Multipart multipart = (Multipart) msgContent;
Log.e("BodyPart", "MultiPartCount: "+multipart.getCount());
for (int j = 0; j < multipart.getCount(); j++) {
BodyPart bodyPart = multipart.getBodyPart(j);
String disposition = bodyPart.getDisposition();
if (disposition != null && (disposition.equalsIgnoreCase("ATTACHMENT"))) { // BodyPart.ATTACHMENT doesn't work for gmail
System.out.println("Mail have some attachment");
DataHandler handler = bodyPart.getDataHandler();
System.out.println("file name : " + handler.getName());
}
else {
System.out.println("Content: "+bodyPart.getContent());
content= bodyPart.getContent().toString();
}
}
}
else
content= messages[i].getContent().toString();
What I know about the problematic mails:
getFrom also return the name i.e it comes in this format FirstName LastName &ltemailID#gmail.com&gt
MultiPart contains 2 BodyParts:
BodyPart 1 returns the content as javax.mail.internet.MimeMultipart#44f2e698
BodyPart 2 returns the correct name for attachment
BodyPart 1 returns the content as
javax.mail.internet.MimeMultipart#44f2e698
Try calling getBodyPart on the MimeMultiPart
That probably returns a MimeBodyPart you can call getContent() on
http://docs.oracle.com/javaee/5/api/javax/mail/internet/MimeBodyPart.html#content
You're probably only handling the simplest case of a text message with attachments. MIME allows much more. You need to learn about the difference between multipart/mixed, multipart/alternative, multipart/related, and multipart/signed. The JavaMail FAQ has more information on handling attachments and the msgshow.java demo program included with the JavaMail download bundle shows how to process messages with nested multiparts.

Categories