Posted at

AndroidからOAuthトークンを利用してGMailを送る

More than 5 years have passed since last update.

SMTPはパスワード認証がデフォらしく,パスワードを利用するサンプルはたくさんあるが,GmailはOAuthのトークンによる認証も出来るので,実際にやってみたサンプル.StackOverflowを参考に実装したが元スレ見つけられなくなってしまったので,手元で動いたコードを下にメモしておく.javamail-androidライブラリを利用している.

前提として, https://mail.google.comに対するトークンはすでに取得できているものとする.

import android.os.AsyncTask;

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

import javax.activation.DataHandler;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.util.ByteArrayDataSource;
import java.util.Properties;

public class GmailSendHelper {
private static final int RESPONSE_CODE_AUTH_SUCCESS = 235;
private static final int SUBMISSION_PORT = 587;
private static final String GMAIL_SMTP_SERVER = "smtp.gmail.com";
private final String userEmail;
private final String authToken;
private Session session;

public GmailSendHelper(String userEmail, String authToken) {
this.userEmail = userEmail;
this.authToken = authToken;
}

private SMTPTransport connectToSmtp(String host, int port)
throws MessagingException {
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);

SMTPTransport transport
= new SMTPTransport(session, /* URL Name */ null);
transport.connect(
host, port, userEmail, /* Password, OAuth認証なのでNull */ null);

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

transport.issueCommand(
"AUTH XOAUTH2 " + new String(response), RESPONSE_CODE_AUTH_SUCCESS);
return transport;
}

public synchronized void sendHtmlMail(
String subject, String body, String recipients)
throws MessagingException {
SMTPTransport smtpTransport
= connectToSmtp(GMAIL_SMTP_SERVER, SUBMISSION_PORT);

MimeMessage message = new MimeMessage(session);
DataHandler handler = new DataHandler(
new ByteArrayDataSource(body.getBytes(), "text/html"));
message.setSender(new InternetAddress(userEmail));
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());
}

public synchronized void sendHtmlMailAsync(
final String subject, final String body, final String recipients) {
AsyncTask<Void, Void, String> task = new AsyncTask<Void, Void, String>() {
@Override
protected String doInBackground(Void... params) {
try {
sendHtmlMail(subject, body, recipients);
return "";
} catch (MessagingException e) {
// TODO: handle error
return e.getMessage();
}
}
};
task.execute();
}
}