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

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();

Related

Javamail Getting one extra file On downloading attachments

I'm getting one extra file of type File on downloading attachments. I'm using MimeBodyPart.saveFile() here is my download attachment code
for (MimeBodyPart mbp : msgToDownload.getAttachmentList()) {
updateProgress(msgToDownload.getAttachmentList().indexOf(mbp),
msgToDownload.getAttachmentList().size());
mbp.saveFile(DOWNLOAD_LOCATION + mbp.getFileName());
}
here msgToDownload is a Class that take Message msg as parameter with some other parameters. And getAttachmentList() is a list of type MimeBodyPart defined as List<MimeBodyPart>
This is how I'm adding attachments to list
sb.setLength(0);
msgToRender.clearAttachments();
Message msg = msgToRender.getMsgRef();
try {
// String messageType = msg.getContentType();
sb.append(getText(msg));
if (hasAttachments(msg)) {
Multipart mp = (Multipart) msg.getContent();
for (int i = mp.getCount() - 1; i >= 0; i--) {
BodyPart bp = mp.getBodyPart(i);
MimeBodyPart mbp = (MimeBodyPart) bp;
msgToRender.addAttachment(mbp);
}
}
}catch(Exception e){
}
Extra file contain attributes of text part of the Mail. Content of extra file
-001a114fd0aa0b377d0546bb84a0 Content-Type: text/plain; charset=UTF-8 please find the attachments... --001a114fd0aa0b377d0546bb84a0 Content-Type: text/html; charset=UTF-8 please find the attachments... --001a114fd0aa0b377d0546bb84a0--
First, you should learn about the isMimeType method.
The problem is most likely that you're not handling multipart/alternative messages. See the sample code in the JavaMail FAQ.

Extracting PST file containing mail as an attachment of PSTMessage

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());
}
}

Attachment Id of emails in java

I am currently working with java mail api . I need to list the attachment details also wants remove the attachment from some emails and forward it to others. So i'm trying to find out the Attachment ID. How can i do it? Any suggestion will be appreciate!!!
Does this help?
private void getAttachments(Part p, File inputFolder, List<String> fileNames) throws Exception{
String disp = p.getDisposition();
if (!p.isMimeType("multipart/*") ) {
if (disp == null || (disp != null && (disp.equalsIgnoreCase(Part.ATTACHMENT) || disp.equalsIgnoreCase(Part.INLINE)))) {
String fileName = p.getFileName();
File opFile = new File(inputFolder, fileName);
((MimeBodyPart) p).saveFile(opFile);
fileNames.add(fileName);
}
}
}else{
Multipart mp = (Multipart) p.getContent();
int count = mp.getCount();
for (int i = 0; i < count; i++){
getAttachments(mp.getBodyPart(i),inputFolder, fileNames);
}
}
}
There ain't anything as an attachment ID. What your mail client displays as a message with attached contents, is really a MIME Multipart and looks like this (sample source):
From: John Doe <example#example.com>
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="XXXXboundary text"
This is a multipart message in MIME format.
--XXXXboundary text
Content-Type: text/plain
this is the body text
--XXXXboundary text
Content-Type: text/plain;
Content-Disposition: attachment; filename="test.txt"
this is the attachment text
--XXXXboundary text--
Important things to note:
Every part in a multipart has a Content-Type
Optionally, there can be a Content-Disposition header
Single parts can be themselves multipart
Note that there is indeed a Content-ID header, but I don't think it's what you are looking for: for example, it is used in multipart/related messages to embed image/*s and text from a text/html in the same email message. You have to understand how it works and if it's used in your input.
I think your best option is to examine the Content-Disposition and the Content-Type header. The rest is guesswork, and without actual requirement one can't help with the code.
Try using the Apache Commons Email package which has a MimeMessageParser class. With the parser you can get the content id (which could be used to identify the attachment) and attachments from the email message like so:
Session session = Session.getInstance(new Properties());
ByteArrayInputStream is = new ByteArrayInputStream(rawEmail.getBytes());
MimeMessage message = new MimeMessage(session, is);
MimeMessageParser parser = new MimeMessageParser(message);
// Once you have the parser, get the content ids and attachments:
List<DataSource> attachments = parser.getContentIds.stream
.map(id -> parser.findAttachmentByCid(id))
.filter(att -> att != null)
.collect(Collectors.toList());
I have created a list here for the sake of brevity, but instead, you could create a map with the contentId as the key and the DataSource as the value.
Take a look at some more examples for using the parser in java here, or some code I wrote for a scala project here.

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.

Send e-mail in Pdf attachment as stream

I want to send a Pdf as an e-mail attachment (I am using the JavaMail API ). I have the Pdf (generated by jasper) as an byte[].
public InputStream exportPdfToInputStream(User user) throws ParseErrorException, MethodInvocationException, ResourceNotFoundException, JRException, IOException{
JasperPrint jasperPrint = createJasperPrintObject(user);
byte[] pdfByteArray = JasperExportManager.exportReportToPdf(jasperPrint);
return new ByteArrayInputStream(pdfByteArray);
}
Here is the code that I am using to construct the MimeBodyPart that will be the attachment:
if (arrayInputStream != null && arrayInputStream instanceof ByteArrayInputStream) {
MimeBodyPart attachment = new MimeBodyPart(arrayInputStream);
attachment.setHeader("Content-Type", "application/pdf");
mimeMultipart.addBodyPart(attachment);
}
This code gives me this error:
javax.mail.MessagingException: IOException while sending message;
nested exception is:
java.io.IOException: Error in encoded stream: needed at least 2 valid base64 characters, but only got 1 before padding character (=), the 10 most recent characters were: "\24\163\193\n\185\194\216#\208="
I have found a solution as suggested in this thread. It seems that there is a DataSource class created just for this purpose. Hope this example will help others also.
if (arrayInputStream != null && arrayInputStream instanceof ByteArrayInputStream) {
// create the second message part with the attachment from a OutputStrean
MimeBodyPart attachment= new MimeBodyPart();
ByteArrayDataSource ds = new ByteArrayDataSource(arrayInputStream, "application/pdf");
attachment.setDataHandler(new DataHandler(ds));
attachment.setFileName("Report.pdf");
mimeMultipart.addBodyPart(attachment);
}
The constructor you used is for parsing a mime part from the transport.
Your second example should work out right. You may consider
not to convert to InputStream and back, this will make unnecessary copies
add a disposition ( e.g. bp.setDisposition(Part.ATTACHMENT); )

Categories