2

Currently we receive an email which gets parsed by

MimeMessageParser mimeMessageParser = parse(message);

and later pull out the attachments with

 if (mimeMessageParser.hasAttachments()) {
     List<DataSource> attachments = mimeMessageParser.getAttachmentList();
     for (DataSource dataSource : attachments) {
         saveAttachment(dataSource, subjectLineProperties, documentToUpload, firstHeaders);
     }
 }

The issue is that getAttachmentList is also returning inline images like in the signature line the business logo, and we do not want to pull out the inline images as attachments. We just want the actual email attachments. ATTACHMENT versus INLINE, but we also have no access to java.mail disposition via the Apache Commons Email 1.4 version, and can't find a solution. I checked their documentation https://commons.apache.org/proper/commons-email/javadocs/api-1.4/index.html

No luck. It seems that the attachments DataSource only allows me to get content and content type and name, but not if it is an inline attachment/image or a regular attachment like Mime Parts can.

bytor99999
  • 726
  • 7
  • 26

2 Answers2

2

I am under impression that there is a workaround without going into lower level... But I haven't checked it with all attachment types yet - only with images. Something like this:

for(DataSource ds : mimeMessageParser.getAttachmentList()) {
    for(String id : mimeMessageParser.getContentIds()) {
        if(ds == mimeMessageParser.findAttachmentByCid(id)) {
            // It is inline attachment with Content ID
            break;
        }
    }
    // If not found - it is file attachment without content ID
}
Andy
  • 21
  • 2
  • 1
    Thanks Andy for the response. For our situation, since this low level code is working perfectly for all attachments, we won't be changing our code. But I do remember trying everything that was in Apache Commons Email and there was no solution. I hope someone new comes along and can try your code and comment if it works. Have a great day. – bytor99999 Jul 02 '20 at 14:35
0

The answer is that Apache Commons Email cannot do such a thing. You have to go lower level and code the old fashioned MimeMessage and MultiPart classes within the JDK in order to make these distinctions.

So from mimeMessageParser.getAttachmentList(); call we now have

        if (mimeMessageParser.hasAttachments()) {
            final Multipart mp = (Multipart) message.getContent();
            if (mp != null) {
                List<DataSource> attachments = extractAttachment(mp);
                for (DataSource dataSource : attachments) {
                    saveAttachment(dataSource, subjectLineProperties, documentToUpload, firstHeaders);
                }
            }
        }


private static List<DataSource> extractAttachment(Multipart multipart) {
    List<DataSource> attachments = new ArrayList<>();
    try {

        for (int i = 0; i < multipart.getCount(); i++) {
            BodyPart bodyPart = multipart.getBodyPart(i);

            if (bodyPart.getContent() instanceof Multipart) {
                // part-within-a-part, do some recursion...
                extractAttachment((Multipart) bodyPart.getContent());
            }

            System.out.println("bodyPart.getDisposition(): " + bodyPart.getDisposition());
            if (!Part.ATTACHMENT.equalsIgnoreCase(bodyPart.getDisposition())) {
                continue; // dealing with attachments only
            }

            InputStream is = bodyPart.getInputStream();
            String fileName = bodyPart.getFileName();
            String contentType = bodyPart.getContentType();
            ByteArrayDataSource dataSource = new ByteArrayDataSource(is, contentType);
            dataSource.setName(fileName);
            attachments.add(dataSource);
        }
    } catch (IOException | MessagingException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    return attachments;
}
bytor99999
  • 726
  • 7
  • 26
  • 1
    what is following line doing in your code?: extractAttachment((Multipart) bodyPart.getContent()); I see it's recursively processing multiparts, but it never adds one or more datasources to the returned attachments list. – Tom Jun 14 '22 at 12:28
  • I apologize as this code was written almost 4 years ago and no longer on this codebase. But the line at the end of the for loop in the try section has attachments.add(dataSource); It looks like that is where it adds each and every attachment/datasource to the List attachments And the recursion when it comes out continues down the code to get to that line, so everything within and at the same level up to the first call all get to that line attachments.add(dataSource) It worked exactly as we needed and never missed an attachment in the almost 3 years it was in production – bytor99999 Jun 14 '22 at 18:16
  • 1
    But on every recursive call you create a new List...sorry, but whatever you add in those new datasource lists is never returned in the initial call of the extractAttachment method. It looks to me like you could just remove that recursive call and the result will be exactly the same. – Tom Jun 15 '22 at 08:03
  • I see, and it never adds those from below up to the calling method's List. As I said it was years ago, and I no longer have access to that code. I would recommend adding the returned list to the above list too. – bytor99999 Jun 15 '22 at 16:29