MessageParser { public List<ParsedAttachment> retrieveAttachments(InputStream fullContent) throws IOException { DefaultMessageBuilder defaultMessageBuilder = new DefaultMessageBuilder(); defaultMessageBuilder.setMimeEntityConfig(MimeConfig.PERMISSIVE); defaultMessageBuilder.setDecodeMonitor(DecodeMonitor.SILENT); Message message = defaultMessageBuilder.parseMessage(fullContent); Body body = message.getBody(); try { if (isAttachment(message, Context.BODY)) { return ImmutableList.of(retrieveAttachment(message)); } if (body instanceof Multipart) { Multipart multipartBody = (Multipart) body; return listAttachments(multipartBody, Context.fromSubType(multipartBody.getSubType())) .collect(Guavate.toImmutableList()); } else { return ImmutableList.of(); } } finally { body.dispose(); } } MessageParser(); List<ParsedAttachment> retrieveAttachments(InputStream fullContent);  }
@Test void getAttachmentsShouldBeEmptyWhenNoAttachment() throws Exception { List<ParsedAttachment> attachments = testee.retrieveAttachments(ClassLoader.getSystemResourceAsStream("eml/noAttachment.eml")); assertThat(attachments).isEmpty(); }
@Test void getAttachmentsShouldRetrieveAttachmentsWhenOneAttachment() throws Exception { List<ParsedAttachment> attachments = testee.retrieveAttachments(ClassLoader.getSystemResourceAsStream("eml/oneAttachmentAndSomeTextInlined.eml")); assertThat(attachments).hasSize(1); }
@Test void getAttachmentsShouldRetrieveAttachmentNameWhenOne() throws Exception { List<ParsedAttachment> attachments = testee.retrieveAttachments(ClassLoader.getSystemResourceAsStream("eml/oneAttachmentAndSomeTextInlined.eml")); assertThat(attachments).hasSize(1); Optional<String> expectedName = Optional.of("exploits_of_a_mom.png"); assertThat(attachments.get(0).getName()).isEqualTo(expectedName); }
@Test void getAttachmentsShouldRetrieveAttachmentNameWhenOneContainingNonASCIICharacters() throws Exception { List<ParsedAttachment> attachments = testee.retrieveAttachments(ClassLoader.getSystemResourceAsStream("eml/messageWithNonASCIIFilenameAttachment.eml")); assertThat(attachments).hasSize(1); assertThat(attachments.get(0).getName()).contains("ديناصور.odt"); }
@Test void getAttachmentsShouldRetrieveEmptyNameWhenNone() throws Exception { List<ParsedAttachment> attachments = testee.retrieveAttachments(ClassLoader.getSystemResourceAsStream("eml/oneAttachmentWithoutName.eml")); assertThat(attachments).hasSize(1); assertThat(attachments.get(0).getName()).isEqualTo(Optional.empty()); }
@Test void getAttachmentsShouldNotFailWhenContentTypeIsNotHere() throws Exception { List<ParsedAttachment> attachments = testee.retrieveAttachments(ClassLoader.getSystemResourceAsStream("eml/oneAttachmentWithoutContentType.eml")); assertThat(attachments).hasSize(1); assertThat(attachments.get(0).getContentType()) .isEqualTo(ContentType.of("application/octet-stream")); }
@Test void getAttachmentsShouldNotFailWhenContentTypeIsEmpty() throws Exception { List<ParsedAttachment> attachments = testee.retrieveAttachments(ClassLoader.getSystemResourceAsStream("eml/oneAttachmentWithEmptyContentType.eml")); assertThat(attachments).hasSize(1); assertThat(attachments.get(0).getContentType()) .isEqualTo(ContentType.of("application/octet-stream")); }
@Test void getAttachmentsShouldRetrieveTheAttachmentContentTypeWhenOneAttachment() throws Exception { List<ParsedAttachment> attachments = testee.retrieveAttachments(ClassLoader.getSystemResourceAsStream("eml/oneAttachmentAndSomeTextInlined.eml")); assertThat(attachments).hasSize(1); assertThat(attachments.get(0).getContentType()) .isEqualTo(ContentType.of("application/octet-stream;\tname=\"exploits_of_a_mom.png\"")); }
@Test void retrieveAttachmentsShouldNotFailOnMessagesWithManyHeaders() throws Exception { List<ParsedAttachment> messageAttachments = testee.retrieveAttachments(ClassLoader.getSystemResourceAsStream("eml/mailWithManyHeaders.eml")); assertThat(messageAttachments).hasSize(1); }
@Test void retrieveAttachmentsShouldNotFailOnMessagesWithLongHeaders() throws Exception { List<ParsedAttachment> messageAttachments = testee.retrieveAttachments(ClassLoader.getSystemResourceAsStream("eml/mailWithLongHeaders.eml")); assertThat(messageAttachments).hasSize(1); }
@Test void getAttachmentsShouldRetrieveTheAttachmentContentTypeWhenOneAttachmentWithSimpleContentType() throws Exception { List<ParsedAttachment> attachments = testee.retrieveAttachments(ClassLoader.getSystemResourceAsStream("eml/oneAttachmentWithSimpleContentType.eml")); assertThat(attachments).hasSize(1); assertThat(attachments.get(0).getContentType()) .isEqualTo(ContentType.of("application/octet-stream")); }
@Test void getAttachmentsShouldRetrieveAttachmentsWhenTwo() throws Exception { List<ParsedAttachment> attachments = testee.retrieveAttachments(ClassLoader.getSystemResourceAsStream("eml/twoAttachments.eml")); assertThat(attachments).hasSize(2); }
@Test void retrieveAttachmentShouldUseFilenameAsNameWhenNoName() throws Exception { List<ParsedAttachment> attachments = testee.retrieveAttachments(ClassLoader.getSystemResourceAsStream("eml/filenameOnly.eml")); assertThat(attachments).hasSize(1) .extracting(ParsedAttachment::getName) .allMatch(Optional::isPresent) .extracting(Optional::get) .containsExactly("inventory.csv"); }
@Test void retrieveAttachmentShouldUseNameWhenBothNameAndFilename() throws Exception { List<ParsedAttachment> attachments = testee.retrieveAttachments(ClassLoader.getSystemResourceAsStream("eml/filenameAndName.eml")); assertThat(attachments).hasSize(1) .extracting(ParsedAttachment::getName) .allMatch(Optional::isPresent) .extracting(Optional::get) .containsExactly("good.csv"); }
@Test void getAttachmentsShouldRetrieveEmbeddedAttachmentsWhenSome() throws Exception { List<ParsedAttachment> attachments = testee.retrieveAttachments(ClassLoader.getSystemResourceAsStream("eml/embeddedAttachmentWithInline.eml")); assertThat(attachments).hasSize(1); }
@Test void getAttachmentsShouldRetrieveInlineAttachmentsWhenSome() throws Exception { List<ParsedAttachment> attachments = testee.retrieveAttachments(ClassLoader.getSystemResourceAsStream("eml/embeddedAttachmentWithAttachment.eml")); assertThat(attachments).hasSize(1); }
@Test void getAttachmentsShouldRetrieveTheAttachmentCIDWhenOne() throws Exception { List<ParsedAttachment> attachments = testee.retrieveAttachments(ClassLoader.getSystemResourceAsStream("eml/oneInlinedAttachment.eml")); assertThat(attachments).hasSize(1); assertThat(attachments.get(0).getCid()).isEqualTo(Optional.of(Cid.from("part1.37A15C92.A7C3488D@linagora.com"))); }
@Test void getAttachementsShouldRetrieveHtmlAttachementsWhenSome() throws Exception { List<ParsedAttachment> attachments = testee.retrieveAttachments(ClassLoader.getSystemResourceAsStream("eml/oneHtmlAttachmentAndSomeTextInlined.eml")); assertThat(attachments).hasSize(1); }
@Test void getAttachementsShouldRetrieveAttachmentsWhenSomeAreInTheMultipartAlternative() throws Exception { List<ParsedAttachment> attachments = testee.retrieveAttachments(ClassLoader.getSystemResourceAsStream("eml/invitationEmailFromOP.eml")); assertThat(attachments).hasSize(7); }
@Test void getAttachmentsShouldNotConsiderUnknownContentDispositionAsAttachments() throws Exception { List<ParsedAttachment> attachments = testee.retrieveAttachments(ClassLoader.getSystemResourceAsStream("eml/unknownDisposition.eml")); assertThat(attachments).hasSize(0); }
@Test void getAttachmentsShouldConsiderNoContentDispositionAsAttachmentsWhenCID() throws Exception { List<ParsedAttachment> attachments = testee.retrieveAttachments(ClassLoader.getSystemResourceAsStream("eml/noContentDispositionWithCID.eml")); assertThat(attachments).hasSize(1); }
@Test void getAttachmentsShouldRetrieveAttachmentsWhenNoCidForInlined() throws Exception { List<ParsedAttachment> attachments = testee.retrieveAttachments(ClassLoader.getSystemResourceAsStream("eml/oneInlinedAttachmentWithNoCid.eml")); assertThat(attachments).hasSize(1); }
@Test void getAttachmentsShouldRetrieveAttachmentsWhenEmptyCidForInlined() throws Exception { List<ParsedAttachment> attachments = testee.retrieveAttachments(ClassLoader.getSystemResourceAsStream("eml/oneInlinedAttachmentWithEmptyCid.eml")); assertThat(attachments).hasSize(1); }
@Test void getAttachmentsShouldRetrieveAttachmentsWhenBlankCidForInlined() throws Exception { List<ParsedAttachment> attachments = testee.retrieveAttachments(ClassLoader.getSystemResourceAsStream("eml/oneInlinedAttachmentWithBlankCid.eml")); assertThat(attachments).hasSize(1); }
@Test void getAttachmentsShouldRetrieveAttachmentsWhenOneFailOnWrongContentDisposition() throws Exception { List<ParsedAttachment> attachments = testee.retrieveAttachments(ClassLoader.getSystemResourceAsStream("eml/multiAttachmentsWithOneWrongContentDisposition.eml")); assertThat(attachments).hasSize(2); }
@Test void getAttachmentsShouldRetrieveOneAttachmentWhenMessageWithAttachmentContentDisposition() throws Exception { List<ParsedAttachment> attachments = testee.retrieveAttachments( ClassLoader.getSystemResourceAsStream("eml/emailWithOnlyAttachment.eml")); assertThat(attachments).hasSize(1); }
@Test void getAttachmentsShouldRetrieveCharset() throws Exception { List<ParsedAttachment> attachments = testee.retrieveAttachments( ClassLoader.getSystemResourceAsStream("eml/charset.eml")); assertThat(attachments).hasSize(1) .first() .satisfies(attachment -> assertThat(attachment.getContentType()) .isEqualTo(ContentType.of("text/calendar; charset=\"iso-8859-1\"; method=COUNTER"))); }
@Test void getAttachmentsShouldRetrieveAllPartsCharset() throws Exception { List<ParsedAttachment> attachments = testee.retrieveAttachments( ClassLoader.getSystemResourceAsStream("eml/charset2.eml")); assertThat(attachments).hasSize(2) .extracting(ParsedAttachment::getContentType) .containsOnly(ContentType.of("text/calendar; charset=\"iso-8859-1\"; method=COUNTER"), ContentType.of("text/calendar; charset=\"iso-4444-5\"; method=COUNTER")); }
@Test void getAttachmentsShouldConsiderICSAsAttachments() throws Exception { List<ParsedAttachment> attachments = testee.retrieveAttachments( ClassLoader.getSystemResourceAsStream("eml/calendar.eml")); assertThat(attachments) .hasSize(1) .extracting(ParsedAttachment::getContentType) .containsExactly(ContentType.of("text/calendar; charset=\"utf-8\"; method=COUNTER")); }
@Test void gpgSignatureShouldBeConsideredAsAnAttachment() throws Exception { List<ParsedAttachment> attachments = testee.retrieveAttachments( ClassLoader.getSystemResourceAsStream("eml/signedMessage.eml")); assertThat(attachments).hasSize(2) .extracting(ParsedAttachment::getName) .allMatch(Optional::isPresent) .extracting(Optional::get) .containsOnly("message suivi", "signature.asc"); }
@Test void mdnReportShouldBeConsideredAsAttachmentWhenDispositionContentType() throws Exception { Message message = MDN.builder() .humanReadableText("A little test") .report(MDNReport.builder() .dispositionField(Disposition.builder() .actionMode(DispositionActionMode.Automatic) .sendingMode(DispositionSendingMode.Automatic) .type(DispositionType.Processed) .build()) .originalMessageIdField("zeugzev@domain.tld") .reportingUserAgentField(ReportingUserAgent.builder().userAgentName("Thunderbird").build()) .finalRecipientField("user@domain.tld") .originalRecipientField("user@domain.tld") .build()) .build() .asMime4JMessageBuilder() .build(); List<ParsedAttachment> result = testee.retrieveAttachments(new ByteArrayInputStream(DefaultMessageWriter.asBytes(message))); assertThat(result).hasSize(1) .allMatch(attachment -> attachment.getContentType().equals(ContentType.of("message/disposition-notification; charset=UTF-8"))); }