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.
I have used this sample programs, 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"
Based on this i follow the next steps:
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 JacksonFactory())
.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
Second Step : Create the Gmail Service based on the credentials:
Gmail gmailService = new Gmail.Builder(httpTransport,
jsonFactory,
credential)
.setApplicationName(APP_NAME)
.build();
Third Step Create 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;
}
Fourth Step Invoke the service:
Message message = _createMessageWithEmail(email);
message = service.users()
.messages()
.send(userId,message)
.execute();
Exception in thread "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??
This is how I managed to get it work with a Google Apps domain:
1.- Using a google apps user open the developer console
2.- Create a new project (ie MyProject)
3.- Go to [Apis & auth] > [Credentials] and create a new [Service Account] client ID
4.- Copy the [service account]'s [Client ID] (the one like xxx.apps.googleusercontent.com) for later use
5.- Now you have to Delegate domain-wide authority to the service account in 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
6.- Go to the [Security] section and find the [Advanced Settings] (it might be hidden so you'd have to click [Show more..])
7.- Click con [Manage API Client Access]
8.- Paste the [Client ID] you previously copied at [4] into the [Client Name] text box.
9.- To grant your app full access to 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)
Now you've done all the settings... now the code:
1.- Create an HttpTransport
private static HttpTransport _createHttpTransport() throws GeneralSecurityException,
IOException {
HttpTransport httpTransport = new NetHttpTransport.Builder()
.trustCertificates(GoogleUtils.getCertificateTrustStore())
.build();
return httpTransport;
}
2.- Create a JSonFactory
private static JsonFactory _createJsonFactory() {
JsonFactory jsonFactory = new JacksonFactory();
return jsonFactory;
}
3.- Create a google credential
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
4.- Create a Gmail Service
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
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.
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 impersonate with this service account.
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;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With