The link in the JavaMail wiki appears to be dead. I updated it to this.
I haven't tried to use OAuth2 with outlook.com myself. I looked at the Microsoft documentation, but I can't figure out where to get a Client ID to even get started. If you've already figured that out, let me know.
After that, I think everything you need is in this article.
I didn't see anything that was specific to Android, which would be very unlikely for Microsoft.
Thanks, that was just the pointer I needed to get started. I was able to test this myself and it works.
After you get your Client ID, browse to this page:
After you go through the login and authorization procedure, it will send you to a URL of this form:
You should see that URL in the browser's URL field. You'll need the code value XXXX for the next step.
Using (e.g.) the curl command line tool, make this request:
-d client_id=CLIENT-ID \
-d redirect_uri=https://login.live.com/oauth20_desktop.srf \
-d client_secret=CLIENT-SECRET \
-d code=XXXX \
-d grant_type=authorization_code \
That will give you a JSON formatted response that includes an Access Token and a Refresh Token (two very long strings). You can use the Access Token as the password, following the instructions on the JavaMail wiki page.
Let me know if that doesn't work for you.
Thank you so much for your help. I was able to successfully get the Access Token and Refresh Token as you mentioned. However, its still not clear what kind of Store to use to actually connect to Outlook.com. Currently, I'm just trying with an IMAPStore as shown in the following code:
IMAPStore store = new IMAPSSLStore(session, null);
logger.info("Trying to connect to "imap-mail.outlook.com with emailAddress@outlook.com");
store.connect("imap-mail.outlook.com", 993, "emailAddress@outlook.com", "");
I get an error that says:
javax.mail.MessagingException: failed to create new store connection; nested exception is: com.sun.mail.iap.ConnectionException: failed to create new store connection
I never get to the "Connected!" log entry. I sincerely appreciate your help with this.
You should never create the Store object directly yourself. You should always use the Session.getStore method. Copy the code from here.
Start by testing with the msgshow.java sample program. Here's how I did it:
java -Dmail.imap.sasl.enable=true \
msgshow -D -U USERNAME@outlook.com -P "$token" -T imap -H imap-mail.outlook.com -f INBOX 1
If you still can't connect, try these debugging tips.
Thank you so much for your help. However, there is still some odd behavior that doesn't make sense to me.
I can successfully connect to the store using the java msgshow program you listed above. However, when I attempt to connect via my JUnit test, the authentication fails. I turned DEBUG on in the session in both the sample app and from my test. I found one subtle difference.
In the sample app, I see the following lines:
DEBUG IMAP: SASL client XOAUTH2
DEBUG IMAP: SASL callback length: 2
DEBUG IMAP: SASL callback 0: javax.security.auth.callback.NameCallback@1fcef4f7
DEBUG IMAP: SASL callback 1: javax.security.auth.callback.PasswordCallback@4c349471
However, from my test, I see the following:
DEBUG IMAP: SASL client XOAUTH2
DEBUG IMAP: SASL callback length: 1
DEBUG IMAP: SASL callback 0: javax.security.auth.callback.NameCallback@24e1e7e8
Please notice how the sample app has 2 callbacks. However, my implementation only has one. Yet, I can't figure out the difference between my code and the sample app. My code looks like the following:
Properties properties = System.getProperties();
// Create the session
Session session = Session.getInstance(properties, null);
// Connect to the store
Store _store = session.getStore("imap");
String accessToken = getHardcodedValue(); // This value matches the value passed in for -P
_store.connect("imap-mail.outlook.com", -1, "email@example.com", accessToken);
When my code gets to the .connect call, the authentication fails. Once again, the main difference I see is the number of callbacks. Yet, I do not understand how this is setup.
Thank you for your continued assistance.
Are you sure the accessToken is being set properly in both cases?