javax.mail: Get nested attachments in EML attachment - java

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.

Related

Issue in reading email via "GMAIL IMAP" using 'javax.mail.Message'

using java reading email via "GMAIL IMAP" using 'javax.mail.Message', if sender is using "mac" device then not able to get attachment's detail as name. Check below code written to fetch attached file name in email :
private void getAttachmentFileName(Message msg) throws MessagingException, IOException {
if (msg.getContent() != null) {
Object content = msg.getContent();
if (content instanceof Multipart) {
MimeMultipart mimeMultipart = (MimeMultipart) msg.getContent();
int numberOfParts = mimeMultipart.getCount();
for (int partCount = 0; partCount < numberOfParts; partCount++) {
MimeBodyPart part = (MimeBodyPart) mimeMultipart.getBodyPart(partCount);
if (part.getFileName() != null) {
System.out.println("fileName :: " + part.getFileName());
}
}
}
}
}
Click here to find debug code where found that details are coming under "BODYSTRUCTURE" but this object is unable to read

Reading Email Attachments Using JavaMail - Reading 'winmail.dat' Rather Than Actual Attachment

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.

Call a java Rest webservice on email event

I have a webservice x exposed.If I get a mail in my email containing attachment I want to call
this webservice.I am not asking for code.I am asking your suggestion in high level how this can be done?
You need REST. So - you cant use org.apache.http.client library. (Other way, if you'll have web service you can use wsimport to create WebService java-client.)
Use javax.mail library to open mailbox and iterate letters.
Process letters. Mark or delete processed letters.
Add crontab/sheduler task to run your app. (As for me, It's better, than create a thread app). Dont forget to use run-one option to prevent double execution.
Here some code example that reads "*.xls" files from mailbox messages:
public void processEmail() throws MessagingException {
Store emailStore = null;
Folder emailFolder = null;
try {
// connecting
Properties properties = new Properties();
properties.setProperty("mail.store.protocol", "imaps");
Session emailSession = Session.getDefaultInstance(properties);
Main.getLog().debug("CONNECT TO : " + config.mailServer + " ["
+ config.mailUser + "] DEBUG: "+config.debug);
// check mailbox
emailStore = emailSession.getStore("imaps");
emailStore.connect(config.mailServer, config.mailUser,
config.mailPassword);
Main.getLog().debug("CONNECT DONE");
emailFolder = emailStore.getFolder("INBOX");
emailFolder.open(Folder.READ_WRITE);
Message[] messages = emailFolder.getMessages();
Main.getLog().debug("RECEIVED " + messages.length + " MESSAGSES");
// for each letter
for (Message message : messages) {
try {
Main.getLog().debug("\nPROCESS LETTER : "
+ message.getSubject());
if (message.getFlags().contains(Flags.Flag.DELETED)) {
continue; // don't process such letters
}
if (message.getFlags().contains(Flags.Flag.SEEN)) {
continue; // don't process such letters
}
//
Map<String, String> parseResult = new HashMap<String, String>();
String auditId = "";
// get file
if (message.getContent() instanceof Multipart) {
Multipart multipart = (Multipart) message.getContent();
for (int i = 0; i < multipart.getCount(); i++) {
BodyPart bodyPart = multipart.getBodyPart(i);
if (!Part.ATTACHMENT.equalsIgnoreCase(bodyPart
.getDisposition())) {
continue;
}
// Process file
if (bodyPart.getFileName().contains(".xls")) {
auditId = maintainExcelFile(bodyPart.getInputStream());
}
}
} else if (message.getContent() instanceof BASE64DecoderStream) {
// Process file
if (message.getFileName().contains(".xls")) {
auditId = maintainExcelFile(((BASE64DecoderStream) message
.getContent()));
}
}
if (!config.debug && auditId!=null && !auditId.equals("")) {
message.setFlag(Flags.Flag.SEEN, true);
}
if (!config.debug) {
sendAcceptMail(message, auditId);
}
} catch (Exception e) {
// Process errors
if (!config.debug) {
message.setFlag(Flags.Flag.SEEN, true);
sendErrorMail(message, e);
}
Main.getLog().error(e.getMessage(), e);
throw new Exception(e);
}
}
} catch (Exception e) {
Main.getLog().error(e.getMessage(), e);
} finally {
emailFolder.close(true);
emailStore.close();
}
}

Parsing MIME message using JavaMail

I'm trying to parse a mime message using the JavaMail API, I did some research but the steps I found doesn't work for me, one of them is what was answered here:
Java Email message Parser?
I'm doing it passing an InputStream as a ByteArrayInputStream came from the content I'm trying to parse.
When I do it, my message.getContent leads to an empty String.
I'm using Scala, btw.
I had this problem recently, so your research couldn't have been that good. When I say recently, I mean the last couple of days! :P
But this is what I did to read the emails (Or at least somewhat read the email. It returns a big chunk of HTML text, which isn't really always pretty in a JEditorPane
private void tableMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_tableMouseReleased
final java.awt.event.MouseEvent e = evt;
Thread t = new Thread(new Runnable() {
#Override
public void run() {
if(table.getRowCount() == 0 || message == null || message.length == 0) {
// Do nothing
} else {
try {
int row = table.rowAtPoint(e.getPoint());
String subject = message[row].getSubject();
String from = InternetAddress.toString(message[row].getFrom());
StringBuilder body = new StringBuilder();
Multipart mp = (Multipart) message[row].getContent();
for(int i = 0; i < mp.getCount(); i++) {
BodyPart bp = mp.getBodyPart(i);
String disp = bp.getDisposition();
if(disp != null && (disp.equals(BodyPart.ATTACHMENT))) {
// Do something
} else {
body.append(bp.getContent());
}
}
EmailContent ec = new EmailContent(new JFrame(),true,from,subject,"<html>" + body.toString());
} catch (IOException ex) {
Logger.getLogger(MailPanel.class.getName()).log(Level.SEVERE, null, ex);
} catch (MessagingException ex) {
Logger.getLogger(MailPanel.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
});
t.start();
}
I had to fill a table with messages and then when you click on a message in the table, it would show a new window with the message in it. The message array is just an array filled with Message objects. So you will obviously need a message to do this. But the part you are after is this:
StringBuilder body = new StringBuilder();
Multipart mp = (Multipart) message[row].getContent();
for(int i = 0; i < mp.getCount(); i++) {
BodyPart bp = mp.getBodyPart(i);
String disp = bp.getDisposition();
if(disp != null && (disp.equals(BodyPart.ATTACHMENT))) {
// Do something
} else {
body.append(bp.getContent());
}
}
It should work, so we'll need more details of what you're doing to figure out what's going wrong.
First, let's make sure the problem isn't with your code and the mail message is correctly formatted. Use the msgshow.java demo program that comes with JavaMail to display the message. Use the -m option and redirect stdin from the file containing the MIME message. What does it display?
If that works correctly, show us the code you're using to read the message.

Can't get email attachments without extension from javax.mail.message

Help please to solve my problem.
I have a function that find email content and attachments:
public void setContentAndAttachmentsList(GMailEmail gMailEmail, Part message) throws MessagingException, IOException {
if (message.isMimeType("text/*") && StringUtils.isEmpty(message.getFileName())) {
gMailEmail.setContent(message.getContent().toString());
log.debug("Found text data. Set as body: " + message.getContent().toString());
} else if (message.isMimeType(MULTIPART_MIME_TYPE)) {
Multipart multipartMessage = (Multipart) message.getContent();
for (int i = 0; i < multipartMessage.getCount(); i++) {
BodyPart messagePart = multipartMessage.getBodyPart(i);
setContentAndAttachmentsList(gMailEmail, messagePart);
}
} else if (StringUtils.isNotBlank(message.getFileName())) {
MailAttachment attachment = new MailAttachment();
attachment.setContentType(message.getContentType());
log.debug("Attachment content type: " + message.getContentType());
attachment.setName(message.getFileName());
log.debug("Attachment file name: " + message.getFileName());
if (message.getContent() instanceof InputStream) {
attachment.setInputStream((InputStream) message.getContent());
} else {
attachment.setInputStream(IOUtils.toInputStream(message.getContent().toString(), UTF_8));
}
List<MailAttachment> attachmentsList = gMailEmail.getAttachmentsList();
attachmentsList.add(attachment);
gMailEmail.setAttachmentsList(attachmentsList);
log.debug("Found attachment" + message.getFileName());
}
}
GMailEmail is POJO.
If email has attachments that have extensions it works perfectly. But when attachments have no extensions, message.getFileName() simply returns null.
I solved this problem.
It must be
StringUtils.isBlank(message.getFileName())
instead of
StringUtils.isEmpty(message.getFileName())
in second line.

Categories

Resources