Gmail REST API:400 Bad Request + Failed Precondition
Posted
技术标签:
【中文标题】Gmail REST API:400 Bad Request + Failed Precondition【英文标题】:Gmail REST API : 400 Bad Request + Failed Precondition 【发布时间】:2015-06-02 09:13:42 【问题描述】:我正在尝试使用 google java api 服务基于 Gmail REST API 发送邮件。我已经通过 Google 开发者控制台配置了一个应用程序客户端并下载了 p12 和 json 文件。
我用过这个示例程序,https://developers.google.com/gmail/api/guides/sending#sending_messages...
此示例有效,但它基于 GoogleAuthorizationCodeFlow。我只想从服务器到服务器工作,直接调用,而不是打开浏览器来获取访问令牌......我得到了它(访问令牌)但最后我收到了一个错误的请求......为什么? ?除了“错误请求”和“先决条件失败”
,我没有收到更多信息基于此,我遵循以下步骤:
第一步:根据我的客户帐户邮件和 p12 生成的文件创建一个 GoogleCredential 对象:
GoogleCredential credential = new GoogleCredential.Builder().setTransport(new NetHttpTransport())
.setJsonFactory(new JacksonFactory())
.setServiceAccountId(serviceAccountUserEmail)
.setServiceAccountScopes(scopes)
.setServiceAccountPrivateKeyFromP12File(
new java.io.File(SERVICE_ACCOUNT_PKCS12_FILE_PATH))
.build();
在这里我必须指出,我在使用 ClientID 而不是 ClientMail 时遇到了很多问题。它必须使用 @developer.gserviceaccount.com 帐户而不是 .apps.googleusercontent.com 。如果你不发送这个参数,你会得到一个“INVALID GRANT”错误。这在这里解释:https://developers.google.com/analytics/devguides/config/mgmt/v3/mgmtAuthorization
第二步:根据凭据创建 Gmail 服务:
Gmail gmailService = new Gmail.Builder(httpTransport,
jsonFactory,
credential)
.setApplicationName(APP_NAME)
.build();
第三步从 MimmeMessage 创建 Google 原始消息:
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;
第四步调用服务:
Message message = _createMessageWithEmail(email);
message = service.users()
.messages()
.send(userId,message)
.execute();
第五步:执行后获取结果...这里我收到异常:
线程“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)
知道什么是错误的或先决条件失败了吗?
【问题讨论】:
你有没有发现哪里出了问题?我有同样的问题。 【参考方案1】:这就是我设法让它与 Google Apps 域一起工作的方法:
1.- 使用谷歌应用程序用户打开 developer console
2.- 创建一个新的项目(即MyProject)
3.- 转到 [Apis & auth] > [Credentials] 并创建一个新的 [Service Account] 客户端 ID
4.- 复制 [service account] 的 [Client ID](例如 xxx.apps.googleusercontent.com)以供以后使用
5.- 现在您必须 Delegate domain-wide authority to the service account 以授权您的应用代表 Google Apps 域中的用户访问用户数据 ...所以去你的google apps domain admin console
6.- 转到 [安全] 部分并找到 [高级设置] (它可能被隐藏,因此您必须单击 [显示更多..])
7.- 点击con [Manage API Client Access]
8.- 将您之前在 [4] 处复制的 [Client ID] 粘贴到 [Client Name] 文本框中。
9.- 要授予您的应用对 gmail 的完全访问权限,请在 [API Scopes] 文本框中输入: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 (输入所有范围非常重要)
现在您已经完成了所有设置...现在是代码:
1.- 创建一个 HttpTransport
private static HttpTransport _createHttpTransport() throws GeneralSecurityException,
IOException
HttpTransport httpTransport = new NetHttpTransport.Builder()
.trustCertificates(GoogleUtils.getCertificateTrustStore())
.build();
return httpTransport;
2.- 创建一个 JSONFactory
private static JsonFactory _createJsonFactory()
JsonFactory jsonFactory = new JacksonFactory();
return jsonFactory;
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 = "xxxx@developer.gserviceaccount.com";
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("user@example.com")
.build();
credential.refreshToken();
return credential;
注意:在 setServiceAccountUser() 方法中使用您的谷歌应用域中的任何用户
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;
现在您可以使用 GmailService 做任何您想做的事情,例如发送电子邮件 ;-) 如 https://developers.google.com/gmail/api/guides/sending 所述
【讨论】:
谢谢。我看问题是我不使用任何帐户来冒充,并且看起来是强制性的?我开了一个新帖子来讨论这个问题:***.com/questions/29341096/… .... 这似乎需要在第 5 步中使用 g-suite。除了个人电子邮件之外,我不需要访问任何内容。一个繁重、复杂且成本高昂的解决方案,可以满足简单的需求。 非常感谢!此外,对于未来的读者:arg "sub" 是阅读电子邮件所必需的。 在第 4 步中,您说“类似 xxx.apps.googleusercontent.com 的那个”。 “服务帐户 ID”看起来像这样(如电子邮件),但如果您在步骤 8 中粘贴它,它似乎可以工作并列出客户端 ID(数字)和范围,但您会收到“failedPrecondition”和“bad请求”,并且如果您尝试冒充“客户端未经授权无法使用此方法检索访问令牌”。解决方法是在第 8 步中使用客户端 ID(一个数字)而不是服务帐户 ID(看起来像电子邮件)。 不确定这是否需要另一个完整的答案,但作为更新 (5/2018 v1.23.0),我还需要将 ServiceAccountPrivateKeyId 和 ServiceAccountProjectId 添加到凭据中以使其正常工作。我确实发现 NateS 提到的表单问题现在可以正常工作 - 您可以粘贴 xxxx@developer.gserviceaccount.com,它会为您将其转换为客户 ID(一个数字),并且可以正常工作。【参考方案2】:非常感谢您的详细回答。我试图使这项工作适用于 asp.net MVC。但是在按照给定步骤完成所有操作后,我的代码给出了同样的错误。
花了 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 = credential,
ApplicationName = "Enquiry Email Sender"
);
var list = service.Users.Messages.List("me").Execute();
var count = "Message Count is: " + list.Messages.Count();
return count;
【讨论】:
以上是关于Gmail REST API:400 Bad Request + Failed Precondition的主要内容,如果未能解决你的问题,请参考以下文章
Gmail REST API:400错误请求+失败的前提条件
我在第79行的REST.php中有400个错误请求,实现了GMAIL Api PHP
SharePoint REST API Online 批处理请求问题:获取 400 Bad Request, odata.error Invalid request
Wordpress wp rest api v2 错误 400 (Bad Request)" Object code: "rest_invalid_param", mes