Search code examples
javaazuremicrosoft-graph-apiemail-attachmentsmsal

Download attachment content using Microsoft Graph API using Java


My requirement is to read email using MSAL and Microsoft Graph API. Once email is read I want to check if attachment is present or not if the attachment is present I want to download the attachment content/contentbytes and save on the local system. Using below code I am able to read email messages details and also attachment details/meta data but not what code to write to download/ the attachment.

package com.xxx.xxxxx.msaltest.client;

import static com.xxx.xxxxxx.msaltest.constants.Constants.AUTHORITY_COMMON_ENDPOINTS;
import static com.xxx.xxxxxx.msaltest.constants.Constants.CLIENT_ID;
import static com.xxx.xxxxxx.msaltest.constants.Constants.SCOPE;

import java.util.List;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;

import org.apache.commons.lang.StringUtils;

//import com.microsoft.graph.requests.GraphServiceClient;
import com.microsoft.aad.msal4j.DeviceCode;
import com.microsoft.aad.msal4j.DeviceCodeFlowParameters;
import com.microsoft.aad.msal4j.IAccount;
import com.microsoft.aad.msal4j.IAuthenticationResult;
import com.microsoft.aad.msal4j.PublicClientApplication;
import com.microsoft.graph.authentication.IAuthenticationProvider;
import com.microsoft.graph.models.Attachment;
import com.microsoft.graph.models.Message;
import com.microsoft.graph.models.User;
import com.microsoft.graph.requests.AttachmentCollectionPage;
import com.microsoft.graph.requests.GraphServiceClient;
import com.microsoft.graph.requests.MessageCollectionPage;

import okhttp3.Request;

public class DeviceCodeClientMsal2 implements Runnable {

public static String COMMON_VARIABLE = StringUtils.EMPTY;

public DeviceCodeClientMsal2() {

}

@Override
public void run() {
    IAuthenticationResult result;
    try {
        result = acquireTokenDeviceCode();
        System.out.println("** Access token: " + result.accessToken());
        System.out.println("** Id token: " + result.idToken());
        System.out.println("** Account username: " + result.account().username());

        IAuthenticationProvider provider = new 
 MyAuthenticationProvider(result.accessToken());

        GraphServiceClient<Request> graphServiceClient = GraphServiceClient.builder()
                .authenticationProvider(provider).buildClient();

        User user = graphServiceClient.me().buildRequest().get();

        final MessageCollectionPage messagePage = 
 graphServiceClient.me().messages().buildRequest().top(3).get();

        List<Message> messageList = messagePage.getCurrentPage();
        for (Message msg : messageList) {
            System.out.println("Subject -> " + msg.subject);
            System.out.println("Body -> " + msg.body.toString());
            System.out.println("Is attachment exist ? " + msg.hasAttachments);
            if (msg.hasAttachments) {
                System.out.println("Message id -> " + msg.id);
                AttachmentCollectionPage attachments = 
graphServiceClient.me().messages(msg.id).attachments()
                        .buildRequest().get();
                List<Attachment> listOfAttachment = attachments.getCurrentPage();
                System.out.println("Size -> " + listOfAttachment.size());
                Attachment attachment = listOfAttachment.get(0);
                System.out.println("Attachment id -> " + attachment.id);
                //How to download the attachment

            }
        }

    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    System.out.println("run method exits");
}

private static IAuthenticationResult acquireTokenDeviceCode() throws Exception {

    // Load token cache from file and initialize token cache aspect. The token cache
    // will have
    // dummy data, so the acquireTokenSilently call will fail.
    System.out.println("Before Public Client Application");
    PublicClientApplication pca = PublicClientApplication.builder(CLIENT_ID).authority(AUTHORITY_COMMON_ENDPOINTS)
            .build();

    // Take first account in the cache. In a production application, you would
    // filter
    // accountsInCache to get the right account for the user authenticating.

    IAuthenticationResult result;
    Consumer<DeviceCode> deviceCodeConsumer = (DeviceCode deviceCode) -> {
        COMMON_VARIABLE = deviceCode.message();
        System.out.println(deviceCode.message());
    };
    DeviceCodeFlowParameters parameters = DeviceCodeFlowParameters.builder(SCOPE, deviceCodeConsumer).build();
    result = pca.acquireToken(parameters).join();
    return result;
}

}


Solution

  • In my case, I used Microsoft Graph Java SDK to download attachment content of email messages.

    You can find below code files that worked in my environment and downloaded attachment files successfully as below:

    DeviceCodeClientAuth.java:

    package com.msaltest.client;
    
    import com.azure.identity.DeviceCodeCredential;
    import com.azure.identity.DeviceCodeCredentialBuilder;
    import com.azure.core.credential.TokenRequestContext;
    import com.microsoft.graph.authentication.IAuthenticationProvider;
    import com.microsoft.graph.models.*;
    import com.microsoft.graph.requests.*;
    import okhttp3.Request;
    import reactor.core.publisher.Mono;
    
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.util.List;
    
    public class DeviceCodeClientAuth implements Runnable {
    
        private static final String CLIENT_ID = "appId";
        private static final String TENANT_ID = "tenantId"; 
        private static final String[] SCOPES = new String[] {"Mail.Read"}; 
    
        public DeviceCodeClientAuth() {
                   System.setProperty("com.microsoft.identity.client.enablePII", "true");
        }
    
        @Override
        public void run() {
            try {
                // Acquire token using Device Code Flow
                DeviceCodeCredential credential = new DeviceCodeCredentialBuilder()
                        .clientId(CLIENT_ID)
                        .tenantId(TENANT_ID)
                        .challengeConsumer(challenge -> {
                            // Display challenge to the user
                            System.out.println(challenge.getMessage());
                        })
                        .build();
    
                if (credential == null) {
                    throw new Exception("Unexpected error: DeviceCodeCredential is null");
                }
    
                IAuthenticationProvider provider = requestUrl -> {
                    TokenRequestContext requestContext = new TokenRequestContext().addScopes(SCOPES);
                    // Get the access token asynchronously
                    Mono<String> futureToken = credential.getToken(requestContext)
                            .map(token -> token.getToken()); 
                    return futureToken.toFuture();   
              };
    
                GraphServiceClient<Request> graphServiceClient = GraphServiceClient
                        .builder()
                        .authenticationProvider(provider)
                        .buildClient();
    
                // Fetch user information
                User user = graphServiceClient.me().buildRequest().get();
                System.out.println("👤 User: " + user.displayName);
    
                // Get messages
                MessageCollectionPage messagePage = graphServiceClient
                        .me()
                        .messages()
                        .buildRequest()
                        .top(3)
                        .get();
    
                List<Message> messageList = messagePage.getCurrentPage();
                for (Message msg : messageList) {
                    System.out.println("📧 Subject: " + msg.subject);
                    System.out.println("📎 Has Attachments? " + msg.hasAttachments);
    
                    if (msg.hasAttachments) {
                        // Only fetch attachments if they exist
                        AttachmentCollectionPage attachments = graphServiceClient
                                .me()
                                .messages(msg.id)
                                .attachments()
                                .buildRequest()
                                .get();
    
                        List<Attachment> listOfAttachment = attachments.getCurrentPage();
                        for (Attachment attachment : listOfAttachment) {
                            System.out.println("🔗 Attachment ID: " + attachment.id);
    
                            if (attachment instanceof FileAttachment) {
                                FileAttachment fileAttachment = (FileAttachment) attachment;
                                System.out.println("⬇ Downloading File: " + fileAttachment.name);
    
                                // Get file content and save locally
                                saveToFile(fileAttachment.name, fileAttachment.contentBytes);
                            } else {
                                System.out.println("📄 Non-file attachment detected: " + attachment.name);
                            }
                        }
                    } else {
                        System.out.println("📧 No attachments for this message.");
                    }
                }
            } catch (Exception e) {
                System.err.println("❌ Error: " + e.getMessage());
                e.printStackTrace();
            }
        }
    
        private static void saveToFile(String fileName, byte[] content) {
            try (FileOutputStream fileOutputStream = new FileOutputStream("downloaded_" + fileName)) {
                fileOutputStream.write(content);
                System.out.println("✅ File saved: downloaded_" + fileName);
            } catch (IOException e) {
                System.err.println("❌ Error saving file: " + e.getMessage());
                e.printStackTrace();
            }
        }
    }
    

    Main.java:

    package com.msaltest.client;  
      
    public class Main {  
        public static void main(String[] args) {  
            System.out.println("Starting Microsoft Graph API Client...");  
              
            DeviceCodeClientAuth client = new DeviceCodeClientAuth();  
            client.run(); // Execute the authentication and email attachment retrieval  
      
      System.out.println("Process completed.");  
        }  
    }
    

    Response:

    enter image description here

    Reference:

    Get attachment - Microsoft Graph