Rendering msg file (with mail attachments) to pdf

Hi,


I am trying to do the following:

  1. Reading msg file and saving the body as rtf
  2. saving mail attachments on the disk
  3. creating pdf from rtf
  4. Attaching email attachment into pdf
But it looks like there is an IO operation involved at every step, which I believe is a network overhead. Can you look at the code and suggest if I can make it any better?

public static void main(String[] args) {
try {
String filePath = “D:\Manish\Tryouts\AsposeEval1\files\”;
String fileName = “msg_attachment_test2”;
//Instantiate an MSG file to load an MSG file from disk
MapiMessage outlookMessageFile = MapiMessage.fromFile(filePath + fileName + “.msg”);

BufferedWriter out = new BufferedWriter(new FileWriter(filePath + fileName + “.rtf”, false));
out.write(outlookMessageFile.getBodyRtf());
out.close();
Document docRTF = new Document(filePath + fileName + “.rtf”);
docRTF.save(filePath + fileName + “.pdf”);

PdfContentEditor editor = new PdfContentEditor();

editor.bindPdf(filePath + fileName + “.pdf”);

MapiAttachmentCollection attColl = outlookMessageFile.getAttachments();

Iterator iter = attColl.iterator();

while (iter.hasNext()) {
MapiAttachment outlookMessageAttachment = iter.next();

//Display attachment type
System.out.println("Att Type : " + outlookMessageAttachment.getAttachmentType());
//Display attached file name
System.out.println("File Name : " + outlookMessageAttachment.getLongFileName());
//Save attachment to the disk
if (outlookMessageAttachment.getLongFileName() != null) {
outlookMessageAttachment.save(filePath + “att\”
+ outlookMessageAttachment.getLongFileName());

Rectangle rect = new Rectangle(10, 10);

String document = filePath + “att\”
+ outlookMessageAttachment.getLongFileName();

editor.createFileAttachment(rect, “This mail has attachments”, document, 1, “PaperClip”);
}

}

editor.save(filePath + fileName + “.pdf”);

} catch (Exception ex) {
System.out.println(ex.toString());
}
}


Thanks,
Manish

Hi Manish,


Most of the load/save methods of classes provide overloaded methods for loading/saving data to/from streams. These overloaded methods can be utilized to reduce the disk I/O.

I have updated the sample code above and tried to use stream to produce the resulting PDF.


public class MsgToPdfTest {
public static void main(String[] args) {
try {
setLicense();
String filePath = “e:\data\folder\”;
String fileName = “filename”;

//Instantiate an MSG file to load an MSG file from disk
MapiMessage outlookMessageFile = MapiMessage.fromFile(filePath + fileName + “.msg”);

// BufferedWriter out = new BufferedWriter(new FileWriter(filePath + fileName + “.rtf”, false));
// out.write(outlookMessageFile.getBodyRtf());
// out.close();
ByteArrayInputStream rtfStream = new ByteArrayInputStream(outlookMessageFile.getBodyRtf().getBytes());

//Document docRTF = new Document(filePath + fileName + “.rtf”);
Document docRTF = new Document(rtfStream);
docRTF.save(filePath + fileName + “.pdf”);

PdfContentEditor editor = new PdfContentEditor();

editor.bindPdf(filePath + fileName + “.pdf”);

MapiAttachmentCollection attColl = outlookMessageFile.getAttachments();

Iterator iter = attColl.iterator();

while (iter.hasNext()) {
MapiAttachment outlookMessageAttachment = iter.next();
//Display attachment type
System.out.println("Att Type : " + outlookMessageAttachment.getAttachmentType());
//Display attached file name
System.out.println("File Name : " + outlookMessageAttachment.getLongFileName());
//Save attachment to the disk
if (outlookMessageAttachment.getLongFileName() != null) {
// outlookMessageAttachment.save(filePath + “att\”
// + outlookMessageAttachment.getLongFileName());
ByteArrayInputStream attStreamIn = new ByteArrayInputStream(outlookMessageAttachment.getBinaryData());
Rectangle rect = new Rectangle(10, 10);
// String document = filePath + “att\”
// + outlookMessageAttachment.getLongFileName();
editor.createFileAttachment(rect, “This mail has attachments”, outlookMessageAttachment.getLongFileName(), attStreamIn, 1, “PaperClip”);
}
}
editor.save(filePath + fileName + “.pdf”);
} catch (Exception ex) {
System.out.println(ex.toString());
}
}

private static void setLicense() throws Exception {
com.aspose.network.License licNetwork = new com.aspose.network.License();
licNetwork.setLicense(“e:\data\aspose\lic\aspose.total.java.lic”);

com.aspose.words.License licWords = new com.aspose.words.License();
licWords.setLicense(“e:\data\aspose\lic\aspose.total.java.lic”);

com.aspose.pdf.kit.License licPdfkit = new com.aspose.pdf.kit.License();
licPdfkit.setLicense(new FileInputStream(“e:\data\aspose\lic\aspose.total.java.lic”));
}
}

Hi Saqib,


Thanks for the code. I tried the same but somehow the attachments were overridden in the loop. e.g. I tried an msg file with 2 attachments and the generated PDF only got the second one however, with the earlier code (saving attachments separately on the disk) I could get both the attachments. I even tried reverting back my earlier code and it worked and I got both attachments.

Can you suggest what am I missing?

Thanks & regards,
Manish Rathore

Hi Manish,


Could you re-check the arguments passed in createFileAttachment() method? The third argument (in case of stream) specifies the file name, which is used as attachment name. It should be different for each of the attachment.

At my end, I tested an MSG file with 4 attachments and all got attached to the PDF document. However, if the file names of attachment in MSG are same, the attachments would be overrided in the PDF. You may concatenate a counter variable in file name to overcome this.

Hi Saqib,


I am now passing the file names as the attachment name but still the problem persists. I can only see the last attachment. Can you tell me what am I missing here?

editor.createFileAttachment(rect, outlookMessageAttachment.getLongFileName(), outlookMessageAttachment.getLongFileName(),
attStreamIn, 1, “PaperClip”);

Regards,
Manish

Hi Manish,


The above statement looks fine and ideally it should add all the attachments with their respective file name. Could you please post the msg file here if possible, so that I could test at my end? You may also zip and send to me using forum options “Contact” --> “send saqib.razzaq an email”.

Hi Saqib,


I have emailed you the msg file that I am using along with the source code and generated pdf.

Regards,
Manish

Hi Manish,


Thanks for sending the sample file and source. When I initially ran it using your java source, I also got 1 attachment in the generated PDF document.

I just enabled the setLicense() method and I could get all attachments in the PDF. It is the evaluation version limitation of Aspose.Pdf.Kit for Java, to add/extract only one attachment. Once you set a temporary/full license, all attachments will be added.

You may get a free 30 days evaluation license by following the instructions at http://www.aspose.com/corporate/purchase/temporary-license.aspx.

Thanks Saqib,


The code is working now.

I have another concerns. With this I can get the body RTF converted to PDF with attachments, but how can I add the email header info (To, From, subject) to the generated PDF?

I tried this but this doesn’t work. Can you help?
//Instantiate an MSG file to load an MSG file from disk
MapiMessage outlookMessageFile = MapiMessage.fromFile(filePath + fileName + “.msg”);

StringBuffer sb = new StringBuffer();
sb.append(“From: " + outlookMessageFile.getSenderName() + " [” + outlookMessageFile.getSenderEmailAddress() + “]\n”);
sb.append("Sent: " + outlookMessageFile.getClientSubmitTime() + “/n”);
sb.append("To: " + outlookMessageFile.getDisplayTo() + “/n”);
sb.append("Subject: " + outlookMessageFile.getSubject() + “/n”);
sb.append(outlookMessageFile.getBody());
outlookMessageFile.setBody(sb.toString());

ByteArrayInputStream rtfStream = new ByteArrayInputStream(outlookMessageFile.getBodyRtf().getBytes());

Document docRTF = new Document(rtfStream);
docRTF.save(filePath + fileName + “.pdf”);
rtfStream.close();

and so on as earlier.

Thanks,
Manish

Hi Manish,


You may add the string (header information prepared using StringBuilder) using Aspose.Words for Java as follows:

// Prepare message header
StringBuffer sb = new StringBuffer();
sb.append(“From: " + outlookMessageFile.getSenderName() + " [” + outlookMessageFile.getSenderEmailAddress() + “]\n”);
// add other header information …

Document docRTF = new Document(rtfStream);
// update: add following 2 lines in your existing source to include the header information
DocumentBuilder builder = new DocumentBuilder(docRTF);
builder.write(sb.toString());
docRTF.save(filePath + fileName + “.pdf”);
rtfStream.close();

For more information on inserting elements to Word documents using Java, please refer to http://www.aspose.com/documentation/java-components/aspose.words-for-java/inserting-document-elements.html.

Hi Saqib,


I have managed to merge email header info and the body RTF into a single PDF. I need your help with the following issues:
  1. null values retrieved for some attributes (Refer PDF file, first 2 lines)
  2. We need the body RTF to append immediately after the header info (not on a new page)
I am mailing you the files separately.

Thanks & regards,
Manish

Hi Manish,


I have sent the updated java source to you via email. It will solve the 2nd issue.

Regarding 1), “Sender Information” and “Sent Date” values are null because the email was in draft mode and this information is not saved in MSG file.

Hi Saqib,


I need your help in two scenarios please.
  1. .msg file with .msg attachment - The generated PDF is corrupted.
  2. .msg file with .msg attachments and other file type attachment - The generated PDF shows all the attachments other than the .msg
Thanks & reagrds,
Manish

Hi Manish,

Please find the updated java source for handling msg files. I have tested it with the following kinds of MSG files at my end:

  • 1. No attachment
  • 2. Non-msg attachments
  • 3. Only msg attachments
  • 4. Msg and non-msg attachments

Aspose.Network handles embedded MSG attachment differently than the other types, so the code needs to be updated for handling msg and non-msg attachments.

Thanks Saqib,


It sure helped.