Shivam Richhariya
Shivam Richhariya

Reputation: 11

How to retrieve office 365 mail file (like image,text file etc) attachment using Oauth Graph Service Client api in java?

Here is how i am getting list of attachment objects attached to a message:

IAttachmentCollectionRequest attachmentsPage = graphClient
    .users(emailServer.getEmailAddress())
    .mailFolders("Inbox")
    .messages(mail.id)
    .attachments()
    .buildRequest();

List<Attachment> attachmentsData = attachmentsPage.get().getCurrentPage();
List<AttachmentData> attachmentDataToStore = new java.util.ArrayList<AttachmentData>();

for(Attachment attachment : attachmentsData)
{
    attachmentData.setInputStream(
        new ByteArrayInputStream(
            attachment.getRawObject()
                .get("contentBytes")
                .getAsString()
                .getBytes()));
}

Now, I believe the conversion of content bytes to input stream is not happening properly and eventually data(image.png) is getting corrupted. Any suggestions?

Upvotes: 0

Views: 1408

Answers (3)

Paul
Paul

Reputation: 1170

as of microsoft-graph version 5.34.0 several things are no longer needed, like decoding, and you'll be ably to simply cast your object.

A convoluted way to get File/ItemAttachments:

List<Attachment> attachments = new ArrayList<>();

        try {
            AttachmentCollectionPage mgAttachmentList =
                    graphClient.users(emailAddress)
                            .messages(mail.id)
                            .attachments()
                            .buildRequest()
                            .get();

            do {
                attachments.addAll(mgAttachmentList.getCurrentPage());

                // Check for next page
                if (mgAttachmentList.getNextPage() != null) {
                    mgAttachmentList = mgAttachmentList.getNextPage().buildRequest().get();
                } else {
                    mgAttachmentList = null;
                }
            } while (mgAttachmentList != null);

            attachments.stream()
                    .filter(Objects::nonNull)
                    .forEach(attachment -> {
                        try {
                            // attachment equals a FileAttachment
                            if ("#microsoft.graph.fileAttachment".equalsIgnoreCase(attachment.oDataType)) {
                                byte[] attachmentContentBytes = ((FileAttachment) attachment).contentBytes;
                                if (attachmentContentBytes != null) {
                                    // your own logic here
                                }
                            } else if ("#microsoft.graph.itemAttachment".equalsIgnoreCase(attachment.oDataType)) {
                                /*
                                 *  We need to convert each Attachment.
                                 *  If it's an ItemAttachment, we need to do another call to retrieve the item-object.
                                 *
                                 *  The standard call with expand option gives us an Attachment (again)
                                 */
                                if (StringUtils.isNotBlank(attachment.contentType)) {
                                    Attachment attachment = graphClient.users(emailAddress)
                                            .messages(mail.id)
                                            .attachments(attachment.id)
                                            .buildRequest()
                                            .expand("microsoft.graph.itemattachment/item")
                                            .get();
                                    if (attachment != null) {
                                        // cast the object to whatever you need, in this example I retrieve the webLink
                                        String linkToMessage = ((Message) ((ItemAttachment) attachment).item).webLink;
                                        // your own logic here
                                    }
                                } else {
                                    log.info("Unknown attachment contentType for an ItemAttachment - Could not read attachment.");
                                }
                            } else {
                                log.error("Unable to read an attachment for mail.");
                            }
                        } catch (Exception e) {
                            log.error("Could not read attachment: '" + attachment.name + "' for message: '" + message.subject + ". " + e.getMessage(), e);
                        }
                    });
        } catch (Exception e) {
            log.error("Something went wrong while receiving attachments for message: '" + message.subject + "'. " + e.getMessage(), e);
        }

Upvotes: 0

RotBot
RotBot

Reputation: 121

Your method of reading contentBytes from the rawObject JSON will work. You just need to use a Base64 decoder instead of String.getBytes() because contentBytes is base64-encoded. This was a bit faster on my network than requesting the attachment again using FileAttachmentRequestBuilder.

IAttachmentCollectionRequest attachmentsPage = graphClient
    .users(emailServer.getEmailAddress())
    .mailFolders("Inbox")
    .messages(mail.id)
    .attachments()
    .buildRequest();

List<Attachment> attachmentsData = attachmentsPage.get().getCurrentPage();
List<AttachmentData> attachmentDataToStore = new java.util.ArrayList<AttachmentData>();

for(Attachment attachment : attachmentsData)
{
    attachmentData.setInputStream(
        new ByteArrayInputStream(
                Base64.getDecoder().decode(attachment.getRawObject()
                    .get("contentBytes")
                    .getAsString());
}

Upvotes: 0

Jason Johnston
Jason Johnston

Reputation: 17702

Use the FileAttachment class to handle all of this for you. Unfortunately the SDK doesn't handle this in the most "clean" manner - you have to request the attachment a second time.

public static void saveAttachments(String accessToken) {
    ensureGraphClient(accessToken);

    final String mailId = "message-id";

    // Get the list of attachments
    List<Attachment> attachments = graphClient
        .me()
        .messages(mailId)
        .attachments()
        .buildRequest()
        // Use select here to avoid getting the content in this first request
        .select("id,contentType,size")
        .get()
        .getCurrentPage();

    for(Attachment attachment : attachments) {
        // Attachment is a base type - need to re-get the attachment as a fileattachment
        if (attachment.oDataType.equals("#microsoft.graph.fileAttachment")) {

            // Use the client to generate the request URL
            String requestUrl = graphClient
                .me()
                .messages(mailId)
                .attachments(attachment.id)
                .buildRequest()
                .getRequestUrl()
                .toString();

            // Build a new file attachment request
            FileAttachmentRequestBuilder requestBuilder =
                new FileAttachmentRequestBuilder(requestUrl, graphClient, null);

            FileAttachment fileAttachment = requestBuilder.buildRequest().get();

            // Get the content directly from the FileAttachment
            byte[] content = fileAttachment.contentBytes;

            try (FileOutputStream stream = new FileOutputStream("C:\\Source\\test.png")) {
                stream.write(content);
            } catch (IOException exception) {
                // Handle it
            }
        }
    }
}

Upvotes: 1

Related Questions