使用nodejs中的服务帐户域范围委派,通过Google Apps Gmail发送邮件

时间:2016-05-15 21:29:06

标签: node.js gmail google-apps jwt service-accounts

我已经阅读了教程并且已经看了2天的例子,但都没有成功。 我想在NodeJS环境中使用Google Apps Gmail帐户发送电子邮件,但是,我收到来自Google API的400回复:

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

这是我到目前为止所做的事情:

  1. 在Google Cloud Platform中创建了一个项目
  2. 创建了一个服务帐户
  3. 为服务帐户启用Domain Wide Delegation
  4. JSON格式
  5. 下载服务帐户的密钥
  6. API Manager> Credentials我创建了OAuth 2.0 client ID
  7. 为项目启用了Gmail API
  8. 在Google Apps管理控制台中:

    1. Security> Advanced Settings> Manage API client access我添加了上面步骤Client ID中的4
    2. 我添加了Client ID
    3. 的所有可能范围

      以下是尝试发送电子邮件的代码:

      const google = require('googleapis');
      const googleKey = require('./google-services.json');
      const jwtClient = new google.auth.JWT(googleKey.client_email, null, googleKey.private_key, ['https://www.googleapis.com/auth/gmail.send'], null);
      
      jwtClient.authorize((err, tokens) => {
        if (err) {
          console.err(err);
          return;
        }
        console.log('Google auth success')
        var gmail = google.gmail({version: 'v1', auth: jwtClient})
        var raw = <build base64 string according to RFC 2822 specification>
      
        var sendMessage = gmail.users.messages.send({
          auth: jwtClient,
          userId: 'user@domain.com',
          message: {
            raw: raw
          }
        }, (err, res) => {
          if (err) {
            console.error(err);
          } else {
            console.log(res);
          }
      });
      

      我可以看到Google auth success消息,并且使用正确初始化的令牌发送请求:

      headers:
      { Authorization: 'Bearer ya29.CjLjAtVjGNJ8fcBnMSS8AEXAvIm4TbyNTc6g_S99HTxRVmzKpWrAv9ioTI4BsLKXW7uojQ',
       'User-Agent': 'google-api-nodejs-client/0.9.8',
       host: 'www.googleapis.com',
       accept: 'application/json',
       'content-type': 'application/json',
       'content-length': 2 }
      

      但是,答案仍为400

2 个答案:

答案 0 :(得分:10)

所以我离解决方案只有半步,问题是在创建const jwtClient = new google.auth.JWT(googleKey.client_email, null, googleKey.private_key, ['https://www.googleapis.com/auth/gmail.send'], null);时我没有提到要冒充的帐户。

正确的初始化应该是: const jwtClient = new google.auth.JWT(googleKey.client_email, null, googleKey.private_key, ['https://www.googleapis.com/auth/gmail.send'], 'user@domain.com');

总而言之,正确的步骤是:

  1. 在Google Cloud Platform中创建了一个项目
  2. 创建了一个服务帐户
  3. 为服务帐户启用Domain Wide Delegation
  4. 以JSON格式下载服务帐户的密钥
  5. API Manager&gt; Credentials我创建了OAuth 2.0 Client ID
  6. 为项目启用了Gmail API
  7. 在Google Apps管理控制台中:

    1. Security&gt; Advanced Settings&gt; Manage API client access我添加了上面第4步中的Client ID
    2. 我添加了Client ID
    3. 的所有可能范围

      这是发送邮件的代码:

      const google = require('googleapis');
      const googleKey = require('./google-services.json');
      const jwtClient = new google.auth.JWT(googleKey.client_email, null, googleKey.private_key, ['https://www.googleapis.com/auth/gmail.send'], '<user to impersonate>');
      
      jwtClient.authorize((err, tokens) => {
        if (err) {
          console.err(err);
          return;
        }
        console.log('Google auth success')
        var gmail = google.gmail({version: 'v1'})
        var raw = <build base64 string according to RFC 2822 specification>
      
        var sendMessage = gmail.users.messages.send({
          auth: jwtClient,
          userId: '<user to impersonate>',
          resource: {
            raw: raw
          }
        }, (err, res) => {
           if (err) {
             console.error(err);
           } else {
             console.log(res);
           }
       });
      

      希望这会对其他人有所帮助

答案 1 :(得分:0)

非常感谢@agoldis。摘要步骤和代码都非常有用。

它帮助我了解了在通信路径的GoogleWorkspace和ApplicationCode端都需要修复的一些内容。下面是我需要的人的c#实现。

private static void Try4()
{
  try {
     //file included in project with properties:  CopyToOutputDirectory = CopyAlways
     var credential = GoogleCredential.FromFile("MyPrj-MyServiceAccount-Credentials.json")       
                      .CreateScoped(new[] { GmailService.Scope.GmailSend })
                      .CreateWithUser("WhoIAmImpersonating@bla.com")
                      .UnderlyingCredential as ServiceAccountCredential;

     var service = new GmailService(new BaseClientService.Initializer() { HttpClientInitializer = credential });

     var nl = Environment.NewLine;
     string plainText =         "From:         WhoIAmImpersonating@bla.com" 
                         + nl + "To:           myfriend@gmail.com,"
                         + nl + "Subject:      This is the Subject" 
                         + nl + "Content-Type: text/html; charset=us-ascii" 
                         + nl 
                         + nl + "This is the message text.";
     var newMsg = new Message() { Raw = Base64UrlEncode(plainText) };

     service.Users.Messages.Send(newMsg, "WhoIAmImpersonating@bla.com").Execute();
     Console.WriteLine("Message Sent OK");
  }
  catch (Exception ex) {
      Console.WriteLine("Message failed");
  }
}



private static string Base64UrlEncode(string input)
{
  var inputBytes = System.Text.Encoding.UTF8.GetBytes(input);
  return Convert.ToBase64String(inputBytes)
                .Replace('+', '-')
                .Replace('/', '_')
                .Replace("=", "" );
}