[英]Gmail Send request results in "insufficient authentication scopes" error
I try to send mail use Gmail API .我尝试使用Gmail API发送邮件。 My code almost the same like in google tutorial, but when I invoice this send Message method I get error Request had insufficient authentication scopes
.我的代码与谷歌教程中的代码几乎相同,但是当我为这个发送消息方法开票时,我收到错误Request had insufficient authentication scopes
。
POST https://gmail.googleapis.com/gmail/v1/users/example.com@gmail.com/messages/send
{
"code": 403,
"details": [
{
"@type": "type.googleapis.com/google.rpc.ErrorInfo",
"reason": "ACCESS_TOKEN_SCOPE_INSUFFICIENT"
}
],
"errors": [
{
"domain": "global",
"message": "Insufficient Permission",
"reason": "insufficientPermissions"
}
],
"message": "Request had insufficient authentication scopes.",
"status": "PERMISSION_DENIED"
}
com.google.api.client.googleapis.json.GoogleJsonResponseException: 403 Forbidden
POST https://gmail.googleapis.com/gmail/v1/users/example.com@gmail.com/messages/send
{
"code": 403,
"details": [
{
"@type": "type.googleapis.com/google.rpc.ErrorInfo",
"reason": "ACCESS_TOKEN_SCOPE_INSUFFICIENT"
}
],
"errors": [
{
"domain": "global",
"message": "Insufficient Permission",
"reason": "insufficientPermissions"
}
],
"message": "Request had insufficient authentication scopes.",
"status": "PERMISSION_DENIED"
}
public class GmailService {
/**
* Application name.
*/
private static final String APPLICATION_NAME = "example.com";
private static final String EXAMPLE_EMAIL = "example.com@gmail.com";
/**
* Global instance of the JSON factory.
*/
private static final JsonFactory JSON_FACTORY = GsonFactory.getDefaultInstance();
/**
* Directory to store authorization tokens for this application.
*/
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 = new ArrayList<>();
private static final String CREDENTIALS_FILE_PATH = "/credentials.json";
/**
* Creates an authorized Credential object.
*
* @param HTTP_TRANSPORT The network HTTP Transport.
* @return An authorized Credential object.
* @throws IOException If the credentials.json file cannot be found.
*/
private Credential getCredentials(final NetHttpTransport HTTP_TRANSPORT) throws IOException {
SCOPES.add(GmailScopes.GMAIL_LABELS);
SCOPES.add(GmailScopes.GMAIL_SEND);
SCOPES.add(GmailScopes.MAIL_GOOGLE_COM);
// Load client secrets.
InputStream in = GmailService.class.getResourceAsStream(CREDENTIALS_FILE_PATH);
if (in == null) {
throw new FileNotFoundException("Resource not found: " + CREDENTIALS_FILE_PATH);
}
final GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(in));
// Build flow and trigger user authorization request.
final GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
HTTP_TRANSPORT, JSON_FACTORY, clientSecrets, SCOPES)
.setDataStoreFactory(new FileDataStoreFactory(new java.io.File(TOKENS_DIRECTORY_PATH)))
.setAccessType("offline")
.build();
LocalServerReceiver receiver = new LocalServerReceiver.Builder().setPort(8888).build();
Credential credential = new AuthorizationCodeInstalledApp(flow, receiver).authorize("user");
//returns an authorized Credential object.
return credential;
}
public boolean sendMessage(String recipientAddress, String subject, String body) throws MessagingException,
IOException, GeneralSecurityException {
Message message = createMessageWithEmail(
createEmail(recipientAddress, EXAMPLE_EMAIL, subject, body));
return createGmail().users()
.messages()
.send(EXAMPLE_EMAIL, message)
.execute()
.getLabelIds().contains("SENT");
}
private MimeMessage createEmail(String to, String from, String subject, String bodyText) throws MessagingException {
MimeMessage email = new MimeMessage(Session.getDefaultInstance(new Properties(), null));
email.setFrom(new InternetAddress(from));
email.addRecipient(javax.mail.Message.RecipientType.TO, new InternetAddress(to));
email.setSubject(subject);
email.setText(bodyText);
return email;
}
private Message createMessageWithEmail(MimeMessage emailContent) throws MessagingException, IOException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
emailContent.writeTo(buffer);
return new Message()
.setRaw(Base64.encodeBase64URLSafeString(buffer.toByteArray()));
}
private Gmail createGmail() throws IOException, GeneralSecurityException {
// Build a new authorized API client service.
final NetHttpTransport HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
return new Gmail.Builder(HTTP_TRANSPORT, JSON_FACTORY, getCredentials(HTTP_TRANSPORT))
.setApplicationName(APPLICATION_NAME)
.build();
}
}
What I neet to do?我需要做什么?
{
"web": {
"client_id": "[REDACTED].googleusercontent.com",
"project_id": "example-3523409",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_secret": "[REDACTED]",
"redirect_uris": [
"http://localhost:8888/Callback",
],
"javascript_origins": [
"http://localhost:4200",
"http://localhost:8888",
"http://localhost:8080"
]
}
}
It looks like your post is mostly code;看起来您的帖子主要是代码; please add some more details.请添加更多细节。
The Gmail.send method requires that the user authencation the application with one of the following scopes in order to run Gmail.send方法要求用户使用以下范围之一验证应用程序才能运行
The error message Request had insufficient authentication scopes.
错误消息Request had insufficient authentication scopes.
means that the currently authencation user has not authorized the application with one of those scopes.表示当前身份验证用户尚未使用这些范围之一授权应用程序。
In your code i can see that you have added在您的代码中,我可以看到您已添加
SCOPES.add(GmailScopes.GMAIL_LABELS);
SCOPES.add(GmailScopes.GMAIL_SEND);
SCOPES.add(GmailScopes.MAIL_GOOGLE_COM);
the Gmail_send scope should be enough. Gmail_send scope 应该足够了。
However your code is storing user tokens in TOKENS_DIRECTORY_PATH.但是,您的代码将用户令牌存储在 TOKENS_DIRECTORY_PATH 中。 Which makes me thing that you previously authorized this user with a reduced scope.这让我觉得你以前用减少的 scope 授权了这个用户。 Then you added the new scopes ran your application again.然后,您添加了新范围,再次运行您的应用程序。 However with the authorization tokens being stored in TOKENS_DIRECTORY_PATH your application is still picking up the old user consent and the old scopes.但是,由于授权令牌存储在 TOKENS_DIRECTORY_PATH 中,您的应用程序仍在获取旧用户同意和旧范围。
Solution is to delete what ever is in TOKENS_DIRECTORY_PATH and run your application again the consent screen should pop up and request authorization of the user again.解决方案是删除 TOKENS_DIRECTORY_PATH 中的内容并再次运行您的应用程序,同意屏幕应弹出并再次请求用户授权。 This time including the proper scopes.这次包括适当的范围。
Note web app:注意 web 应用程序:
You appear to be using web app credentials yet the code you are using is for AuthorizationCodeInstalledApp.您似乎正在使用 web 应用程序凭据,但您使用的代码用于 AuthorizationCodeInstalledApp。 This code may not work if you try hosting it on a web server.如果您尝试将其托管在 web 服务器上,此代码可能不起作用。
Unless you are using JavaScript you don't need to set the javascript_origins in your credentials.除非您使用的是 JavaScript,否则您不需要在凭据中设置 javascript_origins。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.