OAuth2認証を使用して、添付ファイル付きGmailを自動送信する
OAuth2認証を使用して、添付ファイル付きGmailを自動送信しようとしたとき、かなりつまづいたので、記事にします。
1.Javamail-androidのダウンロード
activation.jar、additionnal.jar、mail.jarをダウンロードし、libsフォルダに入れます。
2.build.gradle (app)
dependencies {
implementation 'com.google.api-client:google-api-client:1.25.0'
implementation 'com.google.oauth-client:google-oauth-client-jetty:1.23.0'
implementation 'com.google.apis:google-api-services-gmail:v1-rev83-1.23.0'
}
3.uses-permissions
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.USE_CREDENTIALS" />
4.OAuth2 AuthTokenの取得
private fun authenticate() {
val manager = AccountManager.get(this@AuthenticationActivity)
val prefs3 = getSharedPreferences("setting3", MODE_PRIVATE)
val editor3 = prefs3.edit()
val previousAuthToken = prefs3.getString("AuthToken", null)
if (previousAuthToken != null) {
manager.invalidateAuthToken("com.google", previousAuthToken)
}
manager.getAuthToken(
Account(mailAddressFrom, "com.google"),
"oauth2:https://www.googleapis.com/auth/gmail.send",
null,
false,
{ future ->
try {
val bundle = future.result
val intent = bundle[AccountManager.KEY_INTENT] as Intent?
// 認証されていない場合は認証許可ダイアログを表示
if (intent != null) {
startActivityForResult.launch(intent)
} else {
val authToken = bundle.getString(AccountManager.KEY_AUTHTOKEN)
editor3.putString("AuthToken", authToken)
editor3.apply()
val prefs = getSharedPreferences("Startup", MODE_PRIVATE)
val editor = prefs.edit()
editor.putString("Authenticate", "authenticate_001")
editor.apply()
finish()
}
} catch (e: OperationCanceledException) {
e.printStackTrace()
} catch (e: IOException) {
e.printStackTrace()
} catch (e: AuthenticatorException) {
e.printStackTrace()
}
},
null
)
}
5.Gmailの送信ルーチン
public class GmailSendHelper {
public GmailSendHelper() {
}
public static MimeMessage createEmailWithAttachment(
InternetAddress[] internetAddressesTo,
String from,
String subject,
String textBody,
File file
) throws MessagingException {
Properties props = new Properties();
Session session = Session.getDefaultInstance(props, null);
MimeMessage email = new MimeMessage(session);
email.setFrom(new InternetAddress(from));
for (InternetAddress internetAddress : internetAddressesTo) {
email.addRecipient(javax.mail.Message.RecipientType.TO, internetAddress);
}
email.setSubject(subject);
MimeBodyPart mimeBodyPart = new MimeBodyPart();
mimeBodyPart.setText(textBody, "utf-8");
Multipart multipart = new MimeMultipart();
multipart.addBodyPart(mimeBodyPart);
mimeBodyPart = new MimeBodyPart();
FileDataSource source = new FileDataSource(file);
mimeBodyPart.setDataHandler(new DataHandler(source));
mimeBodyPart.setFileName(file.getName());
multipart.addBodyPart(mimeBodyPart);
email.setContent(multipart);
return email;
}
public static Message createMessageWithEmail(MimeMessage emailContent)
throws MessagingException, IOException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
emailContent.writeTo(buffer);
byte[] bytes = buffer.toByteArray();
String encodedEmail = Base64.encodeBase64URLSafeString(bytes);
Message message = new Message();
message.setRaw(encodedEmail);
return message;
}
public static Message sendMessage(
Gmail service,
String userId,
MimeMessage emailContent
) throws MessagingException, IOException {
Message message = createMessageWithEmail(emailContent);
message = service.users().messages().send(userId, message).execute();
return message;
}
}
6.Gmail送信ルーチンの呼び出し
AccountManager manager = AccountManager.get(this);
manager.getAuthToken(new Account(mailAddressFrom, "com.google"),
"oauth2:https://www.googleapis.com/auth/gmail.send",
null,
false,
new AccountManagerCallback<Bundle>() {
@Override
public void run(AccountManagerFuture<Bundle> future) {
try {
bundle = future.getResult();
AsyncSendEmail asyncSendEmail = new AsyncSendEmail();
asyncSendEmail.execute();
} catch (OperationCanceledException | IOException | AuthenticatorException e) {
e.printStackTrace();
}
}
}, null);
private static class AsyncSendEmail {
private class AsyncRunnable implements Runnable {
Handler handler = new Handler(Looper.getMainLooper());
@Override
public void run() {
// ここにバックグラウンド処理を書く
try {
String authToken = bundle.getString(AccountManager.KEY_AUTHTOKEN);
final NetHttpTransport HTTP_TRANSPORT = new com.google.api.client.http.javanet.NetHttpTransport();
Gmail service = new Gmail.Builder(HTTP_TRANSPORT, JSON_FACTORY, getCredentials(authToken))
.setApplicationName(APPLICATION_NAME)
.build();
assert resultOfExport.filePath != null;
GmailSendHelper.sendMessage(
service,
mailAddressFrom,
GmailSendHelper.createEmailWithAttachment(
internetAddressesTo,
mailAddressFrom,
resultOfExport.mailSubject,
resultOfExport.mailText,
new File(resultOfExport.filePath)
)
);
} catch (MessagingException | IOException e) {
e.printStackTrace();
}
handler.post(new Runnable() {
@Override
public void run() {
onPostExecute();
}
});
}
}
void onPreExecute() {
// ここに前処理を記述します
// 例) プログレスダイアログ表示
transmissionStatus = DURING_TRANSMISSION;
}
void execute() {
onPreExecute();
ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.submit(new AsyncRunnable());
}
void onPostExecute() {
// バックグランド処理終了後の処理をここに記述します
// 例) プログレスダイアログ終了
transmissionStatus = END_OF_TRANSMISSION;
}
}
7.API ConsoleでクライアントIDを登録する。
https://console.developers.google.com/apis/credentials
で認証情報を獲得します。「認証情報を作成」→「ウィザードで選択」を選択します。
名前:適当な名前を付けます。
署名証明書フィンガープリント(デバッグ時:Windows):
keytool -exportcert -alias androiddebugkey -keystore "%USERPROFILE%\.android\debug.keystore" -list -v
署名証明書フィンガープリント(リリース時:Windows):
keytool -exportcert -keystore [jksファイルのフルパス] -list -v
上記を実行:
パスワード(リリース時):jksファイルに設定したパスワード
→SHA1のフィンガープリントをコピーして、上記「OAuthクライアントIDの作成」に貼り付ける。
(2018/10/21追記) Google Play アプリ署名を有効にして、Android App Bundleとしてリリースする場合、署名証明書のフィンガープリントには、Google Developer Consoleの「アプリのリリース」→「アプリの署名」の「アプリへの署名証明書」のSHA1フィンガープリントを持ってくる必要があります。keytoolで出力したフィンガープリントではうまくいきませんので、ご注意を!!
これで、コンパイル・デバッグすれば、自動でOAuth2認証を行い、添付メール付きメールを自動送信してくれます。