java Gmail REST API:400 错误请求 + 失败的前提条件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/29327846/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 15:04:05  来源:igfitidea点击:

Gmail REST API : 400 Bad Request + Failed Precondition

javarestgoogle-cloud-endpointsgmail-api

提问by Azimuts

I'm trying to send mails based on Gmail REST API using google java api services. I have configured through Google Develover Console an application client and downloaded p12 and json files.

我正在尝试使用 google java api 服务发送基于 Gmail REST API 的邮件。我已经通过 Google Develover Console 配置了一个应用程序客户端并下载了 p12 和 json 文件。

I have used this sample programs, https://developers.google.com/gmail/api/guides/sending#sending_messages...

我使用过这个示例程序,https://developers.google.com/gmail/api/guides/sending#sending_messages...

This sample works, but this is based on GoogleAuthorizationCodeFlow. I want just to work from server-to-server, invoking directly, not opening a browser to get an access token... and I got it (the access token) but finally i receive a Bad Request.... Why??? I don't receive more info just than "Bad Request" and "Precondition Failed"

此示例有效,但这是基于 GoogleAuthorizationCodeFlow。我只想从服务器到服务器工作,直接调用,而不是打开浏览器来获取访问令牌......我得到了它(访问令牌)但最后我收到了一个错误的请求......为什么? ? 我没有收到比“错误请求”和“前提条件失败”更多的信息

Based on this i follow the next steps:

基于此,我遵循以下步骤:

  1. First Step: Create a GoogleCredential object based on my client account mail and p12 generated file:

    GoogleCredential  credential = new GoogleCredential.Builder().setTransport(new NetHttpTransport())
                                        .setJsonFactory(new HymansonFactory())
                                        .setServiceAccountId(serviceAccountUserEmail)
                                        .setServiceAccountScopes(scopes)
                                        .setServiceAccountPrivateKeyFromP12File(
                                                    new java.io.File(SERVICE_ACCOUNT_PKCS12_FILE_PATH))                             
                                                            .build();
    
  1. 第一步:根据我的客户帐户邮件和 p12 生成的文件创建一个 GoogleCredential 对象:

    GoogleCredential  credential = new GoogleCredential.Builder().setTransport(new NetHttpTransport())
                                        .setJsonFactory(new HymansonFactory())
                                        .setServiceAccountId(serviceAccountUserEmail)
                                        .setServiceAccountScopes(scopes)
                                        .setServiceAccountPrivateKeyFromP12File(
                                                    new java.io.File(SERVICE_ACCOUNT_PKCS12_FILE_PATH))                             
                                                            .build();
    

Here i have to point that i had many issues for ussing ClientID instead of ClientMail. It must use @developer.gserviceaccount.com account instead of .apps.googleusercontent.com . If u don't send this params ok , u get an "INVALID GRANT" error. This is explained here: https://developers.google.com/analytics/devguides/config/mgmt/v3/mgmtAuthorization

在这里我必须指出,我在使用 ClientID 而不是 ClientMail 时遇到了很多问题。它必须使用 @developer.gserviceaccount.com 帐户而不是 .apps.googleusercontent.com 。如果您不发送此参数,您会收到“无效授权”错误。这在这里解释:https: //developers.google.com/analytics/devguides/config/mgmt/v3/mgmtAuthorization

  1. Second Step: Create the Gmail Service based on the credentials:

    Gmail gmailService = new Gmail.Builder(httpTransport,
                                                  jsonFactory,
                                                  credential)
                                                .setApplicationName(APP_NAME)
                                                    .build();
    
  2. Third StepCreate a Google raw message from a MimmeMessage:

    private static Message _createMessageWithEmail(final MimeMessage email) throws MessagingException, IOException {
    
    ByteArrayOutputStream bytes = new ByteArrayOutputStream();
    email.writeTo(bytes);
    String encodedEmail =       Base64.encodeBase64URLSafeString(bytes.toByteArray());      
    Message message = new Message();    
    message.setRaw(encodedEmail);
    return message;
    

    }

  3. Fourth StepInvoke the service:

        Message message = _createMessageWithEmail(email);
    message = service.users()
    .messages()
    .send(userId,message)
    .execute();
    
  4. Fifth Step: Get Result after execution...Here i receive the exception:
  1. 第二步:根据凭据创建 Gmail 服务:

    Gmail gmailService = new Gmail.Builder(httpTransport,
                                                  jsonFactory,
                                                  credential)
                                                .setApplicationName(APP_NAME)
                                                    .build();
    
  2. 第三步从 MimmeMessage 创建一个谷歌原始消息:

    private static Message _createMessageWithEmail(final MimeMessage email) throws MessagingException, IOException {
    
    ByteArrayOutputStream bytes = new ByteArrayOutputStream();
    email.writeTo(bytes);
    String encodedEmail =       Base64.encodeBase64URLSafeString(bytes.toByteArray());      
    Message message = new Message();    
    message.setRaw(encodedEmail);
    return message;
    

    }

  3. 第四步调用服务:

        Message message = _createMessageWithEmail(email);
    message = service.users()
    .messages()
    .send(userId,message)
    .execute();
    
  4. 第五步:执行后获取结果...这里我收到异常:

Exception in thread "main"

线程“main”中的异常

com.google.api.client.googleapis.json.GoogleJsonResponseException: 400 Bad Request
{
  "code" : 400,
  "errors" : [ {
    "domain" : "global",
    "message" : "Bad Request",
    "reason" : "failedPrecondition"
  } ],
  "message" : "Bad Request"
}
    at com.google.api.client.googleapis.json.GoogleJsonResponseException.from(GoogleJsonResponseException.java:145)

Any idea what is wrong or which is the Precondition failed??

知道出了什么问题还是先决条件失败了?

回答by futuretelematics

This is how I managed to get it work with a Google Apps domain:

这是我设法让它与 Google Apps 域一起使用的方法:

1.- Using a google apps user open the developer console

1.- 使用谷歌应用程序用户打开开发者控制台

2.- Create a new project(ie MyProject)

2.- 创建一个新项目(即MyProject

3.- Go to [Apis & auth] > [Credentials] and create a new [Service Account]client ID

3.- 转到 [Apis & auth] > [Credentials] 并创建一个新的[Service Account]客户端 ID

4.- Copy the [service account]'s [Client ID] (the one like xxx.apps.googleusercontent.com) for later use

4.- 复制[service account]的[Client ID](比如xxx.apps.googleusercontent.com)以备后用

5.- Now you have to Delegate domain-wide authority to the service accountin order to authorize your appl to access user data on behalf of users in the Google Apps domain ... so go to your google apps domain admin console

5.- 现在您必须将域范围的权限委派给服务帐户,以便授权您的应用程序代表 Google Apps 域中的用户访问用户数据......所以请转到您的Google Apps 域管理控制台

6.- Go to the [Security] section and find the [Advanced Settings] (it might be hidden so you'd have to click [Show more..])

6.- 转到 [安全] 部分并找到 [高级设置] (它可能被隐藏,因此您必须单击 [显示更多..])

7.- Click con [Manage API Client Access]

7.- 单击 con [管理 API 客户端访问]

8.- Paste the [Client ID] you previously copied at [4] into the [Client Name] text box.

8.- 将您之前在 [4] 处复制的 [Client ID] 粘贴到 [Client Name] 文本框中。

9.- To grant your app full accessto gmail, at the [API Scopes] text box enter: https://mail.google.com, https://www.googleapis.com/auth/gmail.compose, https://www.googleapis.com/auth/gmail.modify, https://www.googleapis.com/auth/gmail.readonly(it's very important that you enter ALL the scopes)

9.-授予您的应用程序完全访问Gmail时,在[API范围]文本框中输入:https://mail.google.comhttps://www.googleapis.com/auth/gmail.composeHTTPS: //www.googleapis.com/auth/gmail.modify, https://www.googleapis.com/auth/gmail.readonly (输入所有范围非常重要)



Now you've done all the settings... now the code:

现在你已经完成了所有的设置……现在是代码:

1.- Create an HttpTransport

1.- 创建一个 HttpTransport

private static HttpTransport _createHttpTransport() throws GeneralSecurityException,
                                                           IOException { 
    HttpTransport httpTransport = new NetHttpTransport.Builder()                                                 
                                                      .trustCertificates(GoogleUtils.getCertificateTrustStore())
                          .build();
    return httpTransport;
}

2.- Create a JSonFactory

2.- 创建一个 JSonFactory

private static JsonFactory _createJsonFactory() {
    JsonFactory jsonFactory = new HymansonFactory();
    return jsonFactory;
}

3.- Create a google credential

3.- 创建一个谷歌凭证

private static GoogleCredential _createCredentialUsingServerToken(final HttpTransport httpTransport,
                                                                  final JsonFactory jsonFactory) throws IOException,
                                                                                                        GeneralSecurityException {
    // Use the client ID when making the OAuth 2.0 access token request (see Google's OAuth 2.0 Service Account documentation).
    String serviceAccountClientID = "327116756300-thcjqf1mvrn0geefnu6ef3pe2sm61i2q.apps.googleusercontent.com"; 

    // Use the email address when granting the service account access to supported Google APIs 
    String serviceAccountUserEmail = "[email protected]";

    GoogleCredential credential = new GoogleCredential.Builder()
                                                .setTransport(httpTransport)
                                                .setJsonFactory(jsonFactory)
                                                .setServiceAccountId(serviceAccountUserEmail)    // requesting the token
                                                .setServiceAccountPrivateKeyFromP12File(new File(SERVER_P12_SECRET_PATH))
                                                .setServiceAccountScopes(SCOPES)    // see https://developers.google.com/gmail/api/auth/scopes
                                                .setServiceAccountUser("[email protected]")
                                                .build();    
    credential.refreshToken();
    return credential;
}

NOTE:At setServiceAccountUser() method use any user from your google apps domain

注意:在 setServiceAccountUser() 方法中使用您的 google 应用程序域中的任何用户

4.- Create a Gmail Service

4.- 创建 Gmail 服务

private static Gmail _createGmailService(final HttpTransport httpTransport,
                                         final JsonFactory jsonFactory,
                                         final GoogleCredential credential) {
    Gmail gmailService = new Gmail.Builder(httpTransport,
                                            jsonFactory,
                                            credential)
                                   .setApplicationName(APP_NAME)
                                   .build();
    return gmailService;
}

Now you can do whatever you want with the GmailService like send an email ;-) as described at https://developers.google.com/gmail/api/guides/sending

现在,您可以使用 GmailService 执行任何您想做的事情,例如发送电子邮件;-) 如https://developers.google.com/gmail/api/guides/sending 所述

回答by mangeshkt

Thank you so much for the detailed answer. I was trying to make this work for asp.net MVC. But after following everything from the given steps, my code was giving same error.

非常感谢您的详细回答。我试图使这项工作适用于 asp.net MVC。但是在按照给定的步骤进行所有操作之后,我的代码给出了同样的错误。

After spending 2 days to solve this error, i could solve this in following way. In ServiceAccountCredential.Initializer constructor, You need to specify the user id you are trying to impersonatewith this service account.

花了 2 天时间解决此错误后,我可以通过以下方式解决此问题。在 ServiceAccountCredential.Initializer 构造函数中,您需要指定您尝试使用此服务帐户模拟的用户 ID

    ServiceAccountCredential credential = new ServiceAccountCredential(
               new ServiceAccountCredential.Initializer(serviceAccountEmail)
               {
                   User = "<USER@YOUR_GSUIT_DOMAIN.COM>",
                   Scopes = new[] { GmailService.Scope.MailGoogleCom }
               }.FromPrivateKey(<YOUR_PRIVATE_KEY>);

    if (credential != null)
                {
                    var service = new GmailService(new BaseClientService.Initializer
                    {
                        HttpClientInitializer = result,
                        ApplicationName = "Enquiry Email Sender"
                    });

                    var list = service.Users.Messages.List("me").Execute();
                    var count = "Message Count is: " + list.Messages.Count();

                    return count;

                }