voodoodyne / subethasmtp

SubEtha SMTP is a Java library for receiving SMTP mail
Other
343 stars 138 forks source link

Attachment Download #92

Open salman-khan01-confiz opened 5 years ago

salman-khan01-confiz commented 5 years ago

Dear All, I want to download attachment received in email, how can I do this with this API?

Looking for help!

Regards, Salman Khan

davidmoten commented 5 years ago

See #84, active fork is at https://github.com/davidmoten/subethasmtp at the moment. The short answer to your question is that you are returned a bunch of bytes (I think called data) which is an SMTP message and you parse it using javax.mail (separate artifact). I'm going to give you a chunk of code to save you some time but don't expect a lot of explanation, I'm relying on you to get the gist of it:

The first method you see is given the data as an InputStream. If you have a byte array at this point just wrap it in new ByteArrayInputStream(bytes).

Hope this helps!

    static SimplifiedMessageImpl createSimplifiedMessage(InputStream is, Date receivedTime) {
        Preconditions.checkNotNull(is);
        Preconditions.checkNotNull(receivedTime);
        Session s = Session.getInstance(new Properties());
        try {
            MimeMessage m = new MimeMessage(s, is);
            String from = ((InternetAddress) m.getFrom()[0]).getAddress();
            if (m.getFrom().length > 1) {
                log.warn("more than one from address!");
            }
            Builder builder = SimplifiedMessageImpl //
                    .builder() //
                    .subject(nullToBlank(m.getSubject())) //
                    .originator(NexusAddressType.PrivateDomainName, NexusAddressSubType.INMARSATC, from) //
                    .destinations(toEmailAddresses(m.getRecipients(RecipientType.TO))) //
                    .blindDestinations(toEmailAddresses(m.getRecipients(RecipientType.BCC))) //
                    .copyDestinations(toEmailAddresses(m.getRecipients(RecipientType.CC))) //
                    .property(MessageSender.PROPERTY_RECEIVED_TIME, receivedTime.getTime() + "");
            if (m.getReplyTo() != null && m.getReplyTo().length > 0) {
                // only support one replyTo address
                builder.replyTo(toEmailAddresses(m.getReplyTo()).get(0));
            }
            Object content = m.getContent();
            if (content instanceof String) {
                return createSimplifiedMessageForStringContent(m, builder, content);
            } else if (content instanceof Multipart) {
                return createSimplifiedMessageForMultipartContent(builder, content);
            } else if (content instanceof InputStream) {
                // add content as attachment
                return builder.attachment(Optional.absent(), Optional.of(m.getContentType()),
                        ByteStreams.toByteArray((InputStream) content)).build();
            } else {
                throw new RuntimeException("unrecognized content type " + content);
            }
        } catch (MessagingException | IOException e) {
            throw new RuntimeException(e);
        }
    }

    private static SimplifiedMessageImpl createSimplifiedMessageForStringContent(MimeMessage m, Builder builder,
            Object content) throws MessagingException, IOException {
        if (m.isMimeType(MIME_TYPE_TEXT_PLAIN) || m.isMimeType(MIME_TYPE_TEXT_HTML)) {
            return builder.body((String) content) //
                    .build();
        } else {
            // defensive code, haven't been able to trigger this path with unit test
            // add content as attachment
            return builder
                    .attachment(Optional.absent(), Optional.of(m.getContentType()),
                            ByteStreams.toByteArray(m.getDataHandler().getInputStream())) //
                    .build();
        }
    }

    private static SimplifiedMessageImpl createSimplifiedMessageForMultipartContent(Builder builder, Object content)
            throws MessagingException, IOException {
        Multipart mp = (Multipart) content;
        boolean bodyFound = false;
        for (int i = 0; i < mp.getCount(); i++) {
            MimeBodyPart bp = (MimeBodyPart) mp.getBodyPart(i);
            // the first body part that has no filename and is of
            if (!bodyFound && bp.getFileName() == null
                    && (bp.isMimeType(MIME_TYPE_TEXT_PLAIN) || bp.isMimeType(MIME_TYPE_TEXT_HTML))) {
                builder.body(new String(ByteStreams.toByteArray(bp.getDataHandler().getInputStream()),
                        StandardCharsets.UTF_8));
                bodyFound = true;
                // keep looping
                continue;
            }
            Optional<String> filename = Optional.fromNullable(bp.getFileName());
            String contentType = bp.getDataHandler().getContentType();
            byte[] arr = ByteStreams.toByteArray(bp.getDataHandler().getInputStream());
            builder.attachment(filename, Optional.of(contentType), arr);
        }
        return builder.build();
    }

    private static String nullToBlank(String s) {
        if (s == null) {
            return "";
        } else {
            return s;
        }
    }

    private static List<SimplifiedAddress> toEmailAddresses(Address[] addresses) throws MessagingException {
        if (addresses == null) {
            return Collections.emptyList();
        } else {
            return Arrays.stream(addresses) //
                    .map(x -> ((InternetAddress) x).getAddress()) //
                    .map(x -> SimplifiedAddressImpl.create(NexusAddressType.FormalNameBuiltInDomainDefinedAttribute,
                            NexusAddressSubType.RFC_822, //
                            x))
                    .collect(Collectors.toList());
        }
    }
peterjurkovic commented 5 years ago

You can do it quite easily using javax.mail.internet.MimeMessage

public class MmsMessageHandlerFactory implements MessageHandlerFactory {

    @Override
    public MessageHandler create(MessageContext ctx) {
        return new Handler(ctx);
    }

    static class Handler implements MessageHandler {

        MessageContext ctx;

        public Handler(MessageContext ctx) {
            this.ctx = ctx;
        }

        @Override
        public void from(String from) throws RejectException {
        }

        @Override
        public void recipient(String recipient) throws RejectException {
        }

        @Override
        public void data(InputStream data) throws RejectException, TooMuchDataException, IOException {
           Session session = Session.getInstance(new Properties());
            try {
                MimeMessage message = new MimeMessage(session, data);
                message.getContent() // will contains body parts
            } catch (MessagingException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void done() {
        }

    }
}