I need to send an email through my app using say the javamail API
(any other mailing service if available will also do). the problem is i do not want to ask the
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" />