I've adapted the Java console application letting users sign-in with username/password to call Microsoft Graph API on behalf of them, but instead of retrieving basic user data to send emails.
However, while the original example works fine (I am getting user email, see commented code below), I am getting this error when sending emails:
Graph service exception Error code: NoPermissionsInAccessToken
Error message: The token contains no permissions, or permissions can not be understood.
For this operation Mail.Send scope needs to be defined in Azure portal and it should be sufficient to use without Admin consent.
I use these Microsoft dependencies:
<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>msal4j</artifactId>
<version>1.6.1</version>
</dependency>
<dependency>
<groupId>com.microsoft.graph</groupId>
<artifactId>microsoft-graph</artifactId>
<version>1.6.0</version>
</dependency>
This is the actual code:
public class MicrosoftGraphMailer {
private final static String CLIENT_APP_ID = "{real-client-app-id}";
private final static String AUTHORITY = "https://login.microsoftonline.com/{real-tenant-id}/";
public static void main(String[] args) throws Exception {
String user = "{real-user}";
String password = "{real-password}";
String token = getUserPasswordAccessToken(user, password).accessToken();
System.out.println(token);
SimpleAuthProvider authProvider = new SimpleAuthProvider(token);
IGraphServiceClient graphClient = GraphServiceClient.builder().authenticationProvider(authProvider).buildClient();
Message message = new Message();
message.subject = "My subject";
ItemBody body = new ItemBody();
body.contentType = BodyType.HTML;
body.content = "<h1>My HTML body</h1>";
message.body = body;
List<Recipient> toRecipientList = new LinkedList<>();
Recipient toRecipient = new Recipient();
EmailAddress emailAddress = new EmailAddress();
emailAddress.address = "{real-recipient}";
toRecipient.emailAddress = emailAddress;
toRecipientList.add(toRecipient);
message.toRecipients = toRecipientList;
graphClient.me()
.sendMail(message, false)
.buildRequest()
.post();
/*
String mail = graphClient.me()
.buildRequest()
.get().mail;
System.out.println(mail);
*/
}
private static IAuthenticationResult getUserPasswordAccessToken(String user, String password) throws Exception {
PublicClientApplication app = PublicClientApplication.builder(CLIENT_APP_ID).authority(AUTHORITY).build();
Set<String> scopes = new HashSet<>(Arrays.asList("Mail.Send"));
UserNamePasswordParameters userNamePasswordParam = UserNamePasswordParameters.builder(
scopes, user, password.toCharArray())
.build();
return app.acquireToken(userNamePasswordParam).get();
}
private static class SimpleAuthProvider implements IAuthenticationProvider {
private String accessToken = null;
public SimpleAuthProvider(String accessToken) {
this.accessToken = accessToken;
}
@Override
public void authenticateRequest(IHttpRequest request) {
request.addHeader("Authorization", "Bearer " + accessToken);
}
}
}
Basically I need console daemon app for sending emails on behalf of me without any user interaction. Credentials will be stored outside the app. I don't need permissions to send emails on behalf of arbitrary user.