如何使用服务帐户在 Spring Boot 2.x 中调用 gmail api?

How do I call the gmail api in Spring Boot 2.x using a service account?

我有一个配置为访问公司用户 gmail 帐户的 GSuite 服务帐户,我在 G Suite 管理控制台中为其提供了所有权限,包括全域访问权限。我创建了一个服务帐户,现在想使用凭据代表他们发送电子邮件。

到目前为止,这是我的代码:

  public void gmailTest(){
  log.info("Gmail test");

  List<String> SCOPES = new ArrayList<String>(GmailScopes.all());
  // List<String> SCOPES = GmailScopes.all();
  InputStream resourceAsStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("Program Name-12345678.json");

  try {
  if(resourceAsStream != null) {
    NetHttpTransport HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();

    log.info("Reading credential file");
    GoogleCredential credential = GoogleCredential.fromStream(resourceAsStream);
    log.info("Creating scopes");
    credential = credential.createScoped(SCOPES);

    log.info("building gmail api service");
    Gmail gmailService = new Gmail.Builder(HTTP_TRANSPORT, JSON_FACTORY, credential).setApplicationName("ept-mailer").build();
    String user = "deusrex@mygenericdomain.com";

    log.info("calling gmail api");
    ListLabelsResponse listResponse = gmailService.users().labels().list(user).execute();
    log.info("call did not error");
    List<Label> labels = listResponse.getLabels();
    if (labels.isEmpty()) {
      System.out.println("No labels found.");
    } else {
      System.out.println("Labels:");
      for (Label label : labels) {
        System.out.printf("- %s\n", label.getName());
      }
    }
  }
  }
  catch (IOException | GeneralSecurityException ex) {
  log.error(ex.getMessage());
  }

这是我的特权:

 Email (Manage labels)  https://www.googleapis.com/auth/gmail.labels 
 https://www.googleapis.com/auth/gmail.metadata 
 Email (Read/Write)  https://www.googleapis.com/auth/gmail.modify 

这是我得到的错误:

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

好的,答案是您必须在创建凭据时指定用户。在 API 的较新版本中,此调用已更改为:.createDelegated()。只需将您希望模拟的用户电子邮件放在那里即可。

 GoogleCredential credential = GoogleCredential.fromStream(resourceAsStream).createDelegated("deusrex@mygenericdomain.com");

我遇到了同样的问题,最后我解决了。我希望该解决方案可以帮助其他人。

创建一个服务帐户并将权限委托给 GSuite。

  1. 转到google 云控制台go-to 服务帐户
  2. 启用 G Suite domain-wide 委派
  3. 复制客户 ID
  4. 登录您的 GSuite 帐户。转到安全 -> API 控制 -> Domain-wide委派
  5. 添加您的客户端 ID 和范围。
  6. 和最终样本java代码:

@Value("${gcp.credentials.file}")
private String CREDENTIALS_FILE_PATH;


private static Credentials getCredentials(String CREDENTIALS_FILE_PATH) throws IOException {
    InputStream in = FileLoaderImpl.getStream(CREDENTIALS_FILE_PATH);
    if (in == null) {
        throw new FileNotFoundException("Resource not found: " + CREDENTIALS_FILE_PATH);
    }
    GoogleCredentials credentials = GoogleCredentials
            .fromStream(in)
            .createDelegated(EMAIL_FROM)
            .createScoped(List.of(GmailScopes.GMAIL_SEND, GmailScopes.GMAIL_LABELS));
    return credentials;
}

private Gmail getGmailService() throws IOException, GeneralSecurityException {
    NetHttpTransport HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
    return new Gmail.Builder(HTTP_TRANSPORT, JSON_FACTORY,
            new HttpCredentialsAdapter(getCredentials(CREDENTIALS_FILE_PATH)))
            .setApplicationName(APPLICATION_NAME)
            .build();
}

@Override
public Message sendMailWithTemplate(StarMail starMail, boolean isHtml) {
    try {
        MimeMessage mimeMessage = EmailUtils.createEmailMessage(starMail, isHtml);
        // MimeMessage mm = EmailUtils.createEmail(toEmail, USER_ID, subject, bodyText);
        Gmail service = getGmailService();
        Message message = EmailUtils.sendMessage(service, USER_ID, mimeMessage);
        LOGGER.info("Message id: {} ", message.getId());
        LOGGER.info(message.toPrettyString());
        return message;
    } catch (IOException | MessagingException | GeneralSecurityException e) {
        LOGGER.error("sending email failed {}", e);
        throw new RuntimeException("sending email failed " + e.getMessage());
    }
}