Java Oauth2 send email using Office 365
Asked Answered
K

0

6

I'm using Java 1.8, Jakarta email (version 2.1.0) to connect to Microsoft 365 using OAuth for authentication with SMTP. Client has required to use Oauth authenticate, not basic smtp authentification. After reading of documentation https://learn.microsoft.com/en-us/exchange/client-developer... and lots other resources I have configured AD to this permissions:

Microsoft Graph    offline_access
Microsoft Graph    User.Read
Microsoft Graph    Mail.Send
Microsoft Graph    openid
Microsoft Graph    IMAP.AccessAsUser.All
Microsoft Graph    SMTP.Send

Office 365 Exchange Online    full_access_as_app
Office 365 Exchange Online    POP.AccessAsApp
Office 365 Exchange Online    Mail.Send
Office 365 Exchange Online    IMAP.AccessAsApp

Activated SMTP client authentication using PowerShell on Azure https://learn.microsoft.com/en-us/exchange/clients...

PS C:\Users\dx-2102> Get-TransportConfig | Format-List SmtpClientAuthenticationDisabled   
SmtpClientAuthenticationDisabled : False

implemented code for send email (Java):

Properties prop = new Properties();
prop.put("mail.smtp.auth", "true");
prop.put("mail.smtp.starttls.enable", "true");
prop.put("mail.smtp.host", emailSettings.getSmtp().getHostname());
prop.put("mail.smtp.port", emailSettings.getSmtp().getPort());
prop.put("mail.debug", "true");
prop.put("mail.debug.auth", "true");
prop.put("mail.smtp.auth.xoauth2.disable", "false");
prop.put("mail.smtp.auth.mechanisms", "XOAUTH2");
prop.put("mail.transport.protocol", "smtp");
prop.put("mail.smtp.auth.login.disable", "true");
prop.put("mail.smtp.auth.plain.disable", "true");

session = Session.getInstance(prop);
session.setDebug(true);
String accessToken = getOAuth2AccessToken();

transport = session.getTransport("smtp");
transport.connect(emailSettings.getSmtp().getHostname(), emailSettings.getSmtp().getPort(), emailSettings.getSmtp().getUsername(), tokenForSmtp(emailSettings.getSmtp().getUsername(), accessToken));
/* -- */ 
transport.sendMessage(mimeMessage, mimeMessage.getAllRecipients());
transport.close();

method for calling/getting token from Azure AD, in response we get a token with expiration time.

String url = "https://login.microsoftonline.com/" + Tenant_ID + "/oauth2/token";

MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
map.add("grant_type", "client_credentials");
map.add("response_type", "code");
map.add("client_id", ClientId);
map.add("client_secret", ClientSecret);
map.add("scope","openid offline_access https%3A%2F%2Foutlook.office365.com%2FSMTP.Send ");

RestTemplate restTemplate = new RestTemplate();
ResponseEntity<AzureResponse> response = restTemplate.postForEntity(url, map, AzureResponse.class);

method for preparing token for sending within the SMTP send-mail process

private String tokenForSmtp(String userName, String accessToken) {
    final String ctrlA=Character.toString((char) 1);
    final String coded= "user=" + userName + ctrlA+"auth=Bearer " + accessToken + ctrlA+ctrlA;
    return Base64.getEncoder().encodeToString(coded.getBytes());
    //base64("user=" + userName + "^Aauth=Bearer " + accessToken + "^A^A")
}

After send of SMTP email I receive error:

AUTH XOAUTH2 dXNlcj1zb2ZhQHNvbHV0aW9uZmFjdG9yeWFnLm9ub...=
535 5.7.3 Authentication unsuccessful [VI1PR0202CA0024.eurprd02.prod.outlook.com]
Error on sending email: 535 5.7.3 Authentication unsuccessful [VI1PR0202CA0024.eurprd02.prod.outlook.com]

Do I need a some other token scope's from Azure AD other then openid, offline_access and https://outlook.office.com/SMTP.Send ? Or do I miss something else in the configuration of Azure? Of someone has a Java example of how it should be done, please feel free to attach it. Also if you have some screenshots of what to set up on the Azure account.

Kimberleekimberley answered 13/10, 2022 at 13:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.