java - API REST de Gmail: 400 Solicitud incorrecta+Precondición fallida
google-cloud-endpoints gmail-api (2)
Estoy tratando de enviar correos basados en la API REST de Gmail usando los servicios de API de Google Java. Configuré a través de Google Develover Console un cliente de aplicación y descargué archivos p12 y json.
He utilizado estos programas de muestra, https://developers.google.com/gmail/api/guides/sending#sending_messages ...
Este ejemplo funciona, pero se basa en GoogleAuthorizationCodeFlow. Solo quiero trabajar de servidor a servidor, invocando directamente, no abriendo un navegador para obtener un token de acceso ... y lo obtuve (el token de acceso) pero finalmente recibo una solicitud incorrecta ... ¿Por qué? ? No recibo más información que "Solicitud incorrecta" y "Error de condición previa"
En base a esto, sigo los siguientes pasos:
-
Primer paso : crear un objeto de credencial de Google basado en el correo de mi cuenta de cliente y el archivo generado p12:
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();
Aquí tengo que señalar que tuve muchos problemas para usar ClientID en lugar de ClientMail. Debe usar la cuenta @ developer.gserviceaccount.com en lugar de .apps.googleusercontent.com. Si no envía estos parámetros, obtendrá un error de "CONCESIÓN NO VÁLIDA". Esto se explica aquí: https://developers.google.com/analytics/devguides/config/mgmt/v3/mgmtAuthorization
-
Segundo paso : crear el servicio de Gmail basado en las credenciales:
Gmail gmailService = new Gmail.Builder(httpTransport, jsonFactory, credential) .setApplicationName(APP_NAME) .build();
-
Tercer paso Cree un mensaje sin formato de Google desde un 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;
}
-
Cuarto paso Invocar el servicio:
Message message = _createMessageWithEmail(email); message = service.users() .messages() .send(userId,message) .execute();
- Quinto paso : Obtener resultado después de la ejecución ... Aquí recibo la excepción:
Excepción en el hilo "principal"
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)
¿Alguna idea de lo que está mal o cuál es la precondición fallida?
Así es como logré que funcione con un dominio de Google Apps:
1.- Usando un usuario de Google Apps, abra la consola del desarrollador
2.- Crear un nuevo proyecto (es decir, MyProject )
3.- Vaya a [Apis y autenticación]> [Credenciales] y cree una nueva ID de cliente [Cuenta de servicio]
4.- Copie el [ID de cliente] de la [cuenta de servicio] (como xxx.apps.googleusercontent.com) para su uso posterior
5.- Ahora debe delegar la autoridad de todo el dominio a la cuenta de servicio para autorizar a su aplicación a acceder a los datos del usuario en nombre de los usuarios en el dominio de Google Apps ... así que vaya a la consola de administración del dominio de Google Apps.
6.- Vaya a la sección [Seguridad] y busque la [Configuración avanzada] (puede estar oculta, por lo que deberá hacer clic en [Mostrar más ...])
7.- Haga clic en [Administrar acceso de cliente API]
8.- Pegue la [ID del cliente] que copió anteriormente en [4] en el cuadro de texto [Nombre del cliente].
9.- Para otorgar a su aplicación acceso completo a gmail, en el cuadro de texto [Ámbitos de API] ingrese: 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 (es muy importante que ingrese TODOS los ámbitos)
Ahora ha hecho todas las configuraciones ... ahora el código:
1.- Crea un HttpTransport
private static HttpTransport _createHttpTransport() throws GeneralSecurityException,
IOException {
HttpTransport httpTransport = new NetHttpTransport.Builder()
.trustCertificates(GoogleUtils.getCertificateTrustStore())
.build();
return httpTransport;
}
2.- Crear un JSonFactory
private static JsonFactory _createJsonFactory() {
JsonFactory jsonFactory = new JacksonFactory();
return jsonFactory;
}
3.- Crea una credencial de google
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;
}
NOTA: en el método setServiceAccountUser () use cualquier usuario de su dominio de aplicaciones de Google
4.- Crea un servicio de 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;
}
Ahora puede hacer lo que quiera con GmailService, como enviar un correo electrónico ;-) como se describe en https://developers.google.com/gmail/api/guides/sending
Muchas gracias por la respuesta detallada. Estaba tratando de hacer que esto funcione para asp.net MVC. Pero después de seguir todo, desde los pasos dados, mi código estaba dando el mismo error.
Después de pasar 2 días para resolver este error, podría resolverlo de la siguiente manera. En el constructor ServiceAccountCredential.Initializer, debe especificar el ID de usuario que intenta suplantar con esta cuenta de servicio.
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;
}