我正在尝试使用Gmail API。我的目的是通过应用程序(以Google条款服务帐户)从我的Gmail帐户发送电子邮件。我已经被以下错误消息困扰了一段时间。 :
com.google.api.client.googleapis.json.GoogleJsonResponseException: 400 Bad Request
{
"code" : 400,
"errors" : [ {
"domain" : "global",
"message" : "Bad Request",
"reason" : "failedPrecondition"
} ],
"message" : "Bad Request"
}
在发布此问题之前,我已经搜索过Google和Stackoverflow。我发现我需要
创建组织,因为我只想在内部使用该应用程序。要创建组织,我需要创建自己的域(在.de TLD中)并在Google中注册。 Google还希望在我的这个域中提供一个电子邮件地址,然后由我提供。
然后,我根据一些Stackoverflow答案的建议,在OAuth集中屏幕和Google云管理员安全页面上为Gmail设置了所有可能的范围。我还设置了域范围的委托,这也是建议的做法。总而言之,据我所知,我已按照各种问题和答案的建议采取了所有必要的步骤。
在我的代码中(见下文),我插入了credential.refreshToken();
语句,以强制更早地访问OAuth例程。这有助于我解决Gmail范围的早期问题。在这里值得注意的是,对GoogleCredential.fromStream()
的调用将创建一个没有范围的凭证。必须进一步调用credential.createScoped()
才能初始化通过OAuth获得的范围。
我第一次尝试使用Gmail是尝试发送简单的电子邮件。这不起作用(与上述错误相同)。因此,我决定使用一个更简单的测试-阅读Gmail帐户上的标签。再次,这不适用于上面显示的错误消息。如下面的代码所示,我不确定Gmail API所需的 appName 和 emailId 使用什么值。因此,我对想到的所有可能的值进行了迭代。
我有以下问题:
ds.de
和ds@ds.de
(使用虚构示例)发送电子邮件,而不是我的Gmail帐户?如果是这样,那么我可能正在尝试做一些不可能的事情。`
public static void main(String[] args) {
testOauthService();
}
public static void testOauthService() {
HttpTransport HTTP_TRANSPORT;
try {
HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
} catch (Exception ex) {
System.out.println("Exception creating HTTPTransport: " + ex.getMessage());
return;
}
final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
System.out.println("public static void testOauthService () called. ");
System.out.println("Credentials file is: " + credentialFile.getAbsolutePath());
if (!credentialFile.exists()) {
System.err.println("The credentials file " + credentialFile.getAbsolutePath() + " does not exist!");
return;
}
String[] scopeEnums = { GmailScopes.MAIL_GOOGLE_COM, GmailScopes.GMAIL_COMPOSE, GmailScopes.GMAIL_INSERT,
GmailScopes.GMAIL_LABELS, GmailScopes.GMAIL_METADATA, GmailScopes.GMAIL_MODIFY,
GmailScopes.GMAIL_READONLY, GmailScopes.GMAIL_SEND, GmailScopes.GMAIL_SETTINGS_BASIC,
GmailScopes.GMAIL_SETTINGS_SHARING };
boolean bFound = false;
String uid = USER_ID;
for (String appName : APP_NAMES) {
try {
System.out.println("App name: " + appName + ", userId = " + uid);
FileInputStream credentialStream = new FileInputStream(credentialFile);
GoogleCredential credential;
credential = GoogleCredential.fromStream(credentialStream, HTTP_TRANSPORT, JSON_FACTORY);
credential = credential.createScoped(Arrays.asList(scopeEnums));
// The following statement is probably not necessary in production. It does however help with diagnosing
// OAuth problems by forcing an earlier access to OAuth and thus easing later diagnosis.
credential.refreshToken();
System.out.println("Token successfully refreshed!");
Gmail.Builder builder = new Gmail.Builder(HTTP_TRANSPORT, JSON_FACTORY, credential);
builder.setApplicationName(appName);
Gmail gmail = builder.build();
Users users = gmail.users();
GetProfile getProfile = users.getProfile(uid);
System.out.println("Profile user id = " + getProfile.getUserId() + ", " + getProfile.toString());
// Lets try to use some simple Gmail functionality - getting a list of the labels.
Gmail.Users.Labels labels = users.labels();
for (String emailId : EMAIL_USER_IDS) {
System.out.println("Trying labels.list() for email id " + emailId);
try {
Gmail.Users.Labels.List labelList = labels.list(emailId);
ListLabelsResponse response = labelList.execute();
System.out.println("labelList.response: " + response.toString());
} catch (Exception ex) {
System.out.println("Exception in label listing: " + ex.getClass().getName() + ": " + ex.getMessage());
continue;
}
System.out.println("Label listing successful with App Name = " + appName + ", User Id = " + uid
+ ", email id = " + emailId);
bFound = true;
}
} catch (Exception ex) {
System.out.println("Exception: " + ex.getClass().getName() + ": " + ex.getMessage());
ex.printStackTrace();
continue;
}
if (bFound)
break;
}
System.out.println("public static void testOauthService () finished");
}
`
答案 0 :(得分:0)
.p12
文件(服务帐户凭据)粘贴到工作路径中,.setServiceAccountId
中指定服务帐户的电子邮件,并且需要在.setServiceAccountUser
中指定希望服务帐户代表的用户的电子邮件。 有效的示例代码:
public static void main(String... args) throws IOException, GeneralSecurityException
{
final NetHttpTransport HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
File pk12=new File("NAMEOFTHEFILE.p12");
String serviceAccount="EMAILOFTHESERVICEACCOUNT";
GoogleCredential getCredentials = new GoogleCredential.Builder()
.setTransport(HTTP_TRANSPORT)
.setJsonFactory(JSON_FACTORY)
.setServiceAccountId(serviceAccount)
.setServiceAccountPrivateKeyFromP12File(pk12)
.setServiceAccountScopes(SCOPES)
.setServiceAccountUser("MAILOFTHEUSERTOIMPERSONATE")
.build();
// Build a new authorized API client service.
Gmail service = new Gmail.Builder(HTTP_TRANSPORT, JSON_FACTORY, getCredentials)
.setApplicationName(APPLICATION_NAME)
.build();
...
答案 1 :(得分:0)
感谢ziganotschka,为您提供建议和帮助。我想使用服务帐户,因为我想将代码集成到现有的IMAP服务中。我已经启用了域范围的服务帐户委派。我尝试了您的建议,将setServiceAccountUser(EMAIL_USER)
添加到GoogleCredential.Builder
呼叫中。
偶然地,如果遵循GoogleCredential
[https://github.com/googleapis/google-api-java-client/blob/master/google-api-client/src/main/java/com/google/api/client/googleapis/auth/oauth2/GoogleCredential.java]中的代码,
可以使用JSON文件而不是p12文件(如您的示例)。
您的帮助使我能够进一步分析我的问题。如果我使用原始的Gmail电子邮件地址作为EMAIL_USER,那么我得到了TokenResponseException: 401 Unauthorized response
。这个原始的Gmail地址
在我创建服务帐户所需创建的域中自然没有注册,并且似乎没有一种简单的方法(经过大量搜索后可以找到)在我的域中进行注册(将其称为 ds.de )。
如果我在网域中使用已注册的电子邮件地址(假设为 ds@ds.de )并尝试发送电子邮件,则会收到错误GoogleJsonResponseException Mail service not enabled
,这也许并不奇怪,因为我的域名是
在Google世界之外。
然后,我想到了出于测试目的在Google世界中创建一个新域的方法-但Google不允许这样做,因为我住在德国,并且只有在一个人居住在特定国家/地区的情况下,才能通过Google创建一个域(https://support.google.com/domains/answer/4639612?hl=en) -德国不是其中之一!
我得出的结论是,因为我住在德国,所以无法使用Gmail API。因此,我将坚持在服务应用程序(已经成功运行了几年)中使用IMAP。我只是想升级到最新标准!
如果您还有其他建议,我很乐意尝试。