使用 Gmail api 通过 Android 应用发送邮件
Posted
技术标签:
【中文标题】使用 Gmail api 通过 Android 应用发送邮件【英文标题】:Use Gmail api for send mail via Android app 【发布时间】:2021-01-17 05:18:42 【问题描述】:我知道有很多教程、问题等,过去几周我一直在努力,但无法弄清楚。
我正在开发一个 android 应用程序,我想使用我的 gmail 帐户向某个电子邮件地址发送电子邮件。
我已阅读所有 Google Developers 文档并尝试了所有示例,但仍然无法实现。
1.首先 - 我必须拥有 G Suite 帐户吗?它没有说我这样做,但Gmail Api overview 在 G Suite 部分下??
如果我不需要 G Suite -
2.这是right guide通过应用发送邮件吗?
如果是这样
3. 我怎样才能获得Gmail service
?我在console.developers.google
中打开了一个项目并得到了OAuth 2.0 Client IDs
json 文件,但是我找不到如何在Android 中使用它来获取凭据的解释。
拜托,我知道这些是个大问题,但我迫切需要帮助。请给我任何答案或正确的链接(我还没有访问过......)。我也将感谢通过聊天/邮件等提供的帮助。
谢谢
编辑 8/10 我现在的代码:
主要活动 调用 AsyncMail
AsyncMail.java
package com.send.mymailapplication;
import android.content.Context;
import android.content.res.AssetManager;
import android.os.AsyncTask;
import com.google.api.client.extensions.android.http.AndroidHttp;
import com.google.api.client.http.HttpRequestInitializer;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.client.util.Base64;
import com.google.api.services.gmail.Gmail;
import com.google.api.services.gmail.GmailScopes;
import com.google.api.services.gmail.model.Message;
import com.google.auth.http.HttpCredentialsAdapter;
import com.google.auth.oauth2.AccessToken;
import com.google.auth.oauth2.GoogleCredentials;
import com.google.common.collect.Lists;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collections;
import java.util.Properties;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
public class AsyncMail extends AsyncTask<String, Void, Void>
Context context;
static HttpTransport HTTP_TRANSPORT = AndroidHttp.newCompatibleTransport();
static JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
public AsyncMail (Context c)
context = c;
@Override
protected Void doInBackground (String... strings)
try
AssetManager assetManager = context.getAssets();
InputStream jsonStream = assetManager.open("mail.json");
// those 2 tryings also works but gave me the same error
/*ServiceAccountCredentials sourceCredentials = ServiceAccountCredentials.fromStream(jsonStream);
sourceCredentials = (ServiceAccountCredentials) sourceCredentials.createScoped(Arrays.asList("https://mail.google.com/", "https://www.googleapis.com/auth/iam"));
GoogleCredential credential = GoogleCredential.fromStream(jsonStream).createScoped(Lists.newArrayList("https://www.googleapis.com/auth/cloud-platform", GmailScopes.MAIL_GOOGLE_COM));
Gmail gmail = new Gmail.Builder(HTTP_TRANSPORT, JSON_FACTORY, credential).build();*/
GoogleCredentials credential = GoogleCredentials.fromStream(jsonStream)
.createScoped(Lists.newArrayList("https://www.googleapis.com/auth/cloud-platform", "https://www.googleapis.com/auth/dialogflow", GmailScopes.MAIL_GOOGLE_COM));
credential.refreshIfExpired();
AccessToken accessToken = credential.getAccessToken ();
String AuthToken = accessToken.getTokenValue ();
HttpRequestInitializer requestInitializer = new HttpCredentialsAdapter (credential);
Gmail gmail = new Gmail.Builder(HTTP_TRANSPORT, JSON_FACTORY, requestInitializer).build();
MimeMessage mimeMessage = createEmail ("avitalh@gmail.com", "sendmail@mail-291708.iam.gserviceaccount.com", "subbb", "bodyyyy");
Message message = createMessageWithEmail(mimeMessage);
gmail.users().messages().send ("sendmail@mail-291708.iam.gserviceaccount.com", message).execute();
catch (IOException | MessagingException e)
e.printStackTrace ();
return null;
private Message createMessageWithEmail (MimeMessage emailContent) throws IOException, MessagingException
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 MimeMessage createEmail(String to, String from, String subject, String bodyText) throws MessagingException
Properties props = new Properties ();
Session session = Session.getDefaultInstance(props, null);
MimeMessage email = new MimeMessage(session);
email.setFrom(new InternetAddress (from));
email.addRecipient(javax.mail.Message.RecipientType.TO,
new InternetAddress(to));
email.setSubject(subject);
email.setText(bodyText);
return email;
我也不确定:
我应该获得哪些凭据?我认为它是ServiceAccountCredentials
,但documentation 说要使用GoogleCredential
,它已被弃用,所以我尝试了GoogleCredentials
我应该使用哪个电子邮件地址作为发件人 - gmail?服务帐户? “我”?有两个地方我应该使用它
我应该如何处理令牌?
在 Google Api 控制台顶部显示“您的免费试用正在等待:立即激活...” - 我必须激活帐户才能使用 api?我不这么认为,但不确定
【问题讨论】:
你知道答案吗:***.com/questions/68738316/… 对不起@user3505444,我不知道。我放弃了使用 Gmail 发送邮件...我使用了另一个 3rd 方 这太疯狂了,过去几年的文档看起来像大 0。谷歌正朝着错误的方向前进。等我弄清楚了,我会发布回复。 @user3505444 是的,这太疯狂了。如果我们不能指望谷歌,还剩下什么?...祝你好运!!! 【参考方案1】:我会尽量回答你的多个问题
不,您不需要 G Suite 帐户即可使用 Gmail API,您可以使用普通 gmail 帐户。
您链接的指南很好,只是认为在应用程序或控制台中,API 使用 REST 架构处理 HTTPs 请求,因此您可以在任何支持 HTTP 请求的平台中使用 API。
最后一点很大程度上取决于您使用的架构,并考虑到我不是 Android 专家。但是“困难”的部分将是获得用户的授权,但我相信你可以正常使用Java。
有用的链接
G Suite for Android Google Services sample Authenticate OAuth2 in Android JAVA Gmail API quicsktart【讨论】:
非常感谢您的回答!关于答案 3,正如我所写,我想使用 my 帐户发送邮件,所以我不需要用户许可,对吧?我只是找不到如何获取凭据。你真的帮了我,谢谢! 无论哪种方式,您都需要使用凭据。你在什么时候卡住了? 我一直在为public static Message sendMessage
方法获取授权的 Gmail API 实例。所有示例都用于选择使用帐户对话框,当我想使用我自己的时。另外,我不确定-您说我需要使用 HTTPS 请求(我可以使用 Volley 来完成),但看起来 Gmail api 不需要它,不是吗?我真的迷路了......这是一个如此基本的事情,我找不到任何完整的解释。非常感谢您的患者!
帐户对话框?考虑到该人(在这种情况下是您)将需要从谷歌平台提供访问权限才能访问您的数据。我强烈建议您阅读有关OAuth2 in native Apps 和OAuth in Java 的文章
我阅读了很多...我有一个基本问题:我是否必须赢得一个域才能使用 Gmail api 从 my 帐户发送电子邮件? G Suite 帐户或同意屏幕的域?我想不通!【参考方案2】:
初始步骤:
您需要使用您的 Google 帐户登录网络浏览器。
如果不这样做,您将收到重定向错误错误 400 等。
将应用添加到谷歌云平台, 为您将使用的所有签名添加 sha-1 密钥
创建一个带有讨厌的重定向 URL 的网络应用程序!
最终的控制台将如下所示:
下载 网络应用 credential.json。将其放入新文件夹 app/resources
Gmail 类快速入门
private static final String APPLICATION_NAME = "com.emable.getlabels" ;
private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
private static final String TOKENS_DIRECTORY_PATH = "tokens";
/**
* Global instance of the scopes required by this quickstart.
* If modifying these scopes, delete your previously saved tokens/ folder.
*/
private static final List<String> SCOPES = Collections.singletonList( GmailScopes.GMAIL_LABELS ) ;
private static final String CREDENTIALS_FILE_PATH = "/credentials.json";
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();
System.out.println("Message id: " + message.getId());
System.out.println(message.toPrettyString());
return message;
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;
private static LocalServerReceiver localServerReceiver = null;
private static AuthorizationCodeInstalledApp localAuthorizationCodeInstalledApp = null;
private static Credential getCredentials(final NetHttpTransport HTTP_TRANSPORT,Context context, String personId) throws IOException
// Load client secrets.
InputStream in = GmailQuickstart.class.getResourceAsStream(CREDENTIALS_FILE_PATH);
if (in == null)
throw new FileNotFoundException("Resource not found: " + CREDENTIALS_FILE_PATH);
GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(in));
// Build flow and trigger user authorization request.
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
HTTP_TRANSPORT, JSON_FACTORY, clientSecrets, SCOPES)
.setDataStoreFactory(new FileDataStoreFactory( context.getFilesDir() )) // new java.io.File(TOKENS_DIRECTORY_PATH)))
.setAccessType("online")
.setApprovalPrompt("force")
.build();
if (localServerReceiver == null)
localServerReceiver = new LocalServerReceiver.Builder().setPort(8888).build();
else
localServerReceiver.stop();
localServerReceiver = new LocalServerReceiver.Builder().setPort(8888).build();
AuthorizationCodeInstalledApp lAuthorizationCodeInstalledApp = new AuthorizationCodeInstalledApp(flow, localServerReceiver)
protected void onAuthorization(AuthorizationCodeRequestUrl authorizationUrl) throws IOException
String url = (authorizationUrl.build());
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
(context).startActivity(browserIntent);
;
return lAuthorizationCodeInstalledApp.authorize("user");
public static void start(Context c,String personId, TextView tview) throws IOException, GeneralSecurityException
// Build a new authorized API client service.
final NetHttpTransport HTTP_TRANSPORT = new com.google.api.client.http.javanet.NetHttpTransport();
Gmail service = new Gmail.Builder(HTTP_TRANSPORT, JSON_FACTORY, getCredentials(HTTP_TRANSPORT, c, personId))
.setApplicationName(APPLICATION_NAME)
.build();
new Handler(Looper.getMainLooper()).post(new Runnable()
@Override
public void run()
Toast toast = Toast.makeText(c,"Gmail service ok", Toast.LENGTH_SHORT);
toast.show();
);
Log.i("TAG", "BLA");
// Print the labels in the user's account.
String userid = "me";
ListLabelsResponse listResponse = service.users().labels().list(userid).execute();
List<Label> labels = listResponse.getLabels();
//service.
if (labels.isEmpty())
Log.i("TAG"," No Labels ");
else
for (Label label : labels)
new Handler(Looper.getMainLooper()).post(new Runnable()
@Override
public void run()
Toast toast = Toast.makeText(c, label.toString(), Toast.LENGTH_SHORT);
toast.show();
);
这个函数可以通过例如 Avtivity 中的按钮调用。
public void SendEmailTest(Context context)
AsyncTask<Void, Void, String> asyncTask = new AsyncTask<Void, Void, String>()
@Override
protected String doInBackground(Void... params)
try
try
// ignore personId, tview your dont really need them
GmailQuickstart.start(context, personId, tview);
catch (IOException e)
e.printStackTrace();
catch (GeneralSecurityException e)
e.printStackTrace();
catch (Exception e)
e.printStackTrace();
return "";
;
;
asyncTask.execute();
添加用户权限:
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_SMS"/>
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.SMS_RECEIVED" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="com.android.vending.BILLING" />
分级:
plugins
id 'com.android.application'
android
compileSdkVersion 30
buildToolsVersion "30.0.3"
repositories
google()
defaultConfig
applicationId " bla bla bla bla bla your app id here"
minSdkVersion 16
targetSdkVersion 30
versionCode 2
versionName "1.0"
multiDexEnabled true
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
buildTypes
release
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
debuggable false
compileOptions
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
buildFeatures
viewBinding true
lintOptions
checkReleaseBuilds false
dependencies
implementation 'androidx.multidex:multidex:2.0.1'
def billing_version = "4.0.0"
implementation 'androidx.appcompat:appcompat:1.3.0'
implementation 'com.google.android.material:material:1.4.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
implementation 'com.google.android.gms:play-services-auth:19.2.0'
implementation 'androidx.navigation:navigation-fragment:2.3.0'
implementation 'androidx.navigation:navigation-ui:2.3.0'
debugImplementation files('app/libs')
debugImplementation fileTree(dir: 'libs', include: ['*.aar', '*.jar'], exclude: [])
implementation fileTree(dir: 'libs', include: ['*.aar', '*.jar'], exclude: [])
testImplementation 'junit:junit:4.+'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
implementation "com.android.billingclient:billing:$billing_version"
implementation 'com.google.api-client:google-api-client:1.23.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'
将 GmailScopes.GMAIL_LABELS 更改为 what ever 上帝帮助我们所有人
【讨论】:
对你有好处!!我已经接受了 aup 并使用第 3 方发送电子邮件...我认为“上帝帮助我们所有人”是一个非常好的总结... :)以上是关于使用 Gmail api 通过 Android 应用发送邮件的主要内容,如果未能解决你的问题,请参考以下文章
将 Android GoogleSignIn 与 GmailScopes.GMAIL_SEND 一起使用(gmail api)
如何使用谷歌联系人api以编程方式将手机联系人同步到android中的gmail
如何在客户端中使用 Firebase Auth gmail 保护 NestJS 中的 API?
如何从我的 Android 应用程序访问新的 Gmail API?