Monday, August 8, 2016

Gmail API configuration issue (in Java)

Leave a Comment

Here is my Gmail service configuration/factory class:

import java.io.File; import java.io.IOException; import java.security.GeneralSecurityException;  import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.env.Environment;  import com.google.api.client.auth.oauth2.Credential; import com.google.api.client.googleapis.auth.oauth2.GoogleCredential; import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport; import com.google.api.client.http.HttpRequestInitializer; import com.google.api.client.http.javanet.NetHttpTransport; import com.google.api.client.json.jackson2.JacksonFactory; import com.google.api.services.gmail.Gmail; import com.google.api.services.gmail.GmailScopes;  public class GmailServiceFactoryBean {      private @Autowired Environment env;      private final NetHttpTransport transport;     private final JacksonFactory jacksonFactory;      public GmailServiceFactoryBean() throws GeneralSecurityException, IOException {         this.transport = GoogleNetHttpTransport.newTrustedTransport();         this.jacksonFactory = JacksonFactory.getDefaultInstance();     }      public Gmail getGmailService() throws IOException, GeneralSecurityException {         return new Gmail.Builder(transport, jacksonFactory, getCredential())                 .setApplicationName(env.getProperty("gmail.api.application.name")).build();     }      private HttpRequestInitializer getCredential() throws IOException, GeneralSecurityException {         File p12File = new File(this.getClass().getClassLoader().getResource("google-key.p12").getFile());          Credential credential = new GoogleCredential.Builder()             .setServiceAccountId(env.getProperty("gmail.api.service.account.email"))             .setServiceAccountPrivateKeyId(env.getProperty("gmail.api.private.key.id"))             .setServiceAccountPrivateKeyFromP12File(p12File)             .setTransport(transport)             .setJsonFactory(jacksonFactory)             .setServiceAccountScopes(GmailScopes.all())             //.setServiceAccountUser(env.getProperty("gmail.api.user.email"))             .build();          credential.refreshToken();          return credential;     }  } 

Here is my inner mailing service that uses previous bean under the hood:

import java.io.ByteArrayOutputStream; import java.io.IOException; import java.security.GeneralSecurityException; import java.util.List; import java.util.Properties;  import javax.mail.MessagingException; import javax.mail.Session; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeMessage; import javax.mail.internet.MimeMessage.RecipientType;  import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.env.Environment; import org.springframework.stereotype.Service;  import com.google.api.client.repackaged.org.apache.commons.codec.binary.Base64; import com.google.api.services.gmail.Gmail; import com.google.api.services.gmail.model.Message; import com.example.factory.GmailServiceFactoryBean; import com.example.service.MailService; import com.example.service.exception.MailServiceException;  @Service public class MailServiceImpl implements MailService {      private @Autowired GmailServiceFactoryBean gmailServiceFactoryBean;     private @Autowired Environment env;      @Override     public void send(com.example.model.Message message, String recipient) throws MailServiceException {         try {             Gmail gmailService = gmailServiceFactoryBean.getGmailService();             MimeMessage mimeMessage = createMimeMessage(message, recipient);             Message gMessage = createMessageWithEmail(mimeMessage);             gmailService.users().messages().send("me", gMessage).execute();         } catch(MessagingException | IOException | GeneralSecurityException e) {             throw new MailServiceException(e.getMessage(), e.getCause());         }     }      @Override     public void send(com.example.model.Message message, List<String> recipients) throws MailServiceException {         for (String recipient : recipients) {             send(message, recipient);         }     }      private MimeMessage createMimeMessage(com.example.model.Message message, String recipient) throws MessagingException {         Session session = Session.getDefaultInstance(new Properties());          MimeMessage email = new MimeMessage(session);         InternetAddress toAddress = new InternetAddress(recipient);         InternetAddress fromAddress = new InternetAddress(env.getProperty("gmail.api.service.account.email"));          email.setFrom(fromAddress);         email.addRecipient(RecipientType.TO, toAddress);         email.setSubject(message.getTitle());         email.setText(message.getContent(), env.getProperty("application.encoding"));          return email;     }      private Message createMessageWithEmail(MimeMessage email) throws MessagingException, IOException {         ByteArrayOutputStream baos = new ByteArrayOutputStream();         email.writeTo(baos);         return new Message().setRaw(Base64.encodeBase64URLSafeString(baos.toByteArray()));     } } 

When I execute method send(Message message, String recipient) of class MailServiceImpl I get following response:

400 Bad Request {   "code" : 400,   "errors" : [ {     "domain" : "global",     "message" : "Bad Request",     "reason" : "failedPrecondition"   } ],   "message" : "Bad Request" } 

Does anyone know what's wrong?

2 Answers

Answers 1

For GMail API to work, you have to "Delegate domain-wide authority to the service account" within your Google Apps account.

Service account doesn't represent a human Google account. You also can't delegate authority to whole Google domain(***@gmail.com).

The other way out could be with OAuth 2.0 for Web Server Applications or Java Mail api

For more do check: GMail REST API: Using Google Credentials Without Impersonate

Answers 2

Check if you have enabled gmail to send mails using 3rd party applications.

Go to my account ->Sign in and Security -> Connected Apps now scroll to the bottom of the page you will get Less secure apps ->change it to on !! Hope this will work

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment