Javamail API in Android Using Xoauth

Javamail api in android using XOauth

I researched this for some days and I found a solution that is working for me at the moment.
I get the oauth2 token from the android AccountManager and then send the email via SMTP using JavaMail. The idea is based on the Java example here http://code.google.com/p/google-mail-oauth2-tools/wiki/JavaSampleCode and on this java Xoauth example here http://google-mail-xoauth-tools.googlecode.com/svn/trunk/java/com/google/code/samples/xoauth/XoauthAuthenticator.java

There's no working SASL implementation in JavaMail for Android and using asmack wasn't working so I didn't use SASL and I issued the command directly like in the Xoauth example above.

I get the token from the acount manager like this

AccountManager am = AccountManager.get(this);
Account me = ...; //You need to get a google account on the device, it changes if you have more than one
am.getAuthToken(me, "oauth2:https://mail.google.com/", null, this, new OnTokenAcquired(), null);

private class OnTokenAcquired implements AccountManagerCallback<Bundle>{
@Override
public void run(AccountManagerFuture<Bundle> result){
try{
Bundle bundle = result.getResult();
token = bundle.getString(AccountManager.KEY_AUTHTOKEN);

} catch (Exception e){
Log.d("test", e.getMessage());
}
}
}

If it works, you have an oauth2 token in token. I use the token in this code

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.Provider;
import java.security.Security;
import java.util.Properties;

import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.URLName;
import javax.mail.Message;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

import android.util.Log;

import com.sun.mail.smtp.SMTPTransport;
import com.sun.mail.util.BASE64EncoderStream;

public class GMailOauthSender {
private Session session;

public SMTPTransport connectToSmtp(String host, int port, String userEmail,
String oauthToken, boolean debug) throws Exception {

Properties props = new Properties();
props.put("mail.smtp.starttls.enable", "true");
props.put("mail.smtp.starttls.required", "true");
props.put("mail.smtp.sasl.enable", "false");
session = Session.getInstance(props);
session.setDebug(debug);

final URLName unusedUrlName = null;
SMTPTransport transport = new SMTPTransport(session, unusedUrlName);
// If the password is non-null, SMTP tries to do AUTH LOGIN.
final String emptyPassword = null;
transport.connect(host, port, userEmail, emptyPassword);

byte[] response = String.format("user=%s\1auth=Bearer %s\1\1", userEmail,
oauthToken).getBytes();
response = BASE64EncoderStream.encode(response);

transport.issueCommand("AUTH XOAUTH2 " + new String(response),
235);

return transport;
}

public synchronized void sendMail(String subject, String body, String user,
String oauthToken, String recipients) {
try {

SMTPTransport smtpTransport = connectToSmtp("smtp.gmail.com",
587,
user,
oauthToken,
true);

MimeMessage message = new MimeMessage(session);
DataHandler handler = new DataHandler(new ByteArrayDataSource(body.getBytes(), "text/plain"));
message.setSender(new InternetAddress(user));
message.setSubject(subject);
message.setDataHandler(handler);
if (recipients.indexOf(',') > 0)
message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(recipients));
else
message.setRecipient(Message.RecipientType.TO, new InternetAddress(recipients));
smtpTransport.sendMessage(message, message.getAllRecipients());

} catch (Exception e) {
Log.d("test", e.getMessage());
}

}

I'm not at all an expert in this and I didn't use any Security provider like in the examples above, not sure how it will affect this but it's working for me.
Hope this helps and that someone can tell me if there's something wrong with this too :p
It's my first answer here so sorry if I did something wrong!

Ops, forgot some other documentation I used: https://developers.google.com/google-apps/gmail/xoauth2_protocol and http://developer.android.com/training/id-auth/authenticate.html

ops again! You also need these permissions in the manifest

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.USE_CREDENTIALS" />

Android Javamail custom Authentication

I have a working jar with sasl support for imap (for smtp you have to issue the command as you said because java mail for android doesn't have the sasl infrastructure for smtp).
All I did was to add the packages javax.security.sasl and javax.security.auth.callback to the java mail for android source and repackage it. I had to put the in a different namaspace, myjavax.security.sasl etc. because otherwise android build system complains that the package contains core libraries, not sure why it doesn't complain for javax.mail which is in a core namespace anyway (javax). I also had to change some import for the new namespace in some classes, but basically are the packeges classes themselves and com.sun.mail.imap.protocol.IMAPSaslAuthenticator.
With this I could successfully authenticate to gmail imap server using the oauth 2 token I got from the Android AccountManager, I didn't try anything else. For smtp, you can look at my answer here Javamail api in android using XOauth
I think it's possible to make smtp work with Sasl getting the new classes from here http://kenai.com/projects/javamail/sources/mercurial/show/mail/src/main/java/com/sun/mail/smtp which have Sasl support for smtp.
I think this is perfectly fine because all I do is adding some GPL classes, the one that I added are from the JDK.
Hope this helps, if you need the jars or some more explanation on how to do it, just ask.

Send Email using JavaMail And OAuth

Why are you doing it the hard way instead of using JavaMail's built in OAuth support?

Javamail gmail and OAuth2

This is an addition to the answer of user2000974. The documentation of Google about using OAuth to authenticate to an IMAP or SMTP server Gmail > IMAP > OAuth 2.0 Mechanism clearly states the following

This document defines the SASL XOAUTH2 mechanism for use with the IMAP AUTHENTICATE and SMTP AUTH commands. This mechanism allows the use of OAuth 2.0 Access Tokens to authenticate to a user's Gmail account.

The scope for IMAP and SMTP access is https://mail.google.com/.

I hope this will direct people that stumble upon this question in the future to the right documentation page.

JavaMail with Oauth and Office365

With a tip from a co-worker without a stackoverflow account, I finally got it to work. The key was that the scopes I used for the OAuth token, are apparantly not allowed for an application. This bit of information is hidden at the bottom of this page.

Summarized, the solution is:

  • You must configure the IMAP.AccessAsApp permission, instead of IMAP.AccessAsUser.All . This permission can not be found in the same place as the AccessAsUser.All permission, but is hidden under "Office 365 Exchange Online" permissions.
  • Unlike what you would expect, you must use the https://outlook.office365.com/.default scope in the body payload for the access token request.

That did the trick. It is ridiculous how much difficulty I had to find that information in the documentation pages using search engines.



Related Topics



Leave a reply



Submit