代码之家  ›  专栏  ›  技术社区  ›  agoldis

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

  •  6
  • agoldis  · 技术社区  · 8 年前

    我已经看了两天的教程和示例了,但都没有成功。 我想在NodeJS环境中使用Google Apps Gmail帐户发送电子邮件,但是,我得到 400 来自谷歌API的回应:

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

    以下是我迄今为止所做的工作:

    1. 在Google云平台中创建项目
    2. 已创建服务帐户
    3. 启用 Domain Wide Delegation 服务帐户的
    4. 已在中下载服务帐户的密钥 JSON 总体安排
    5. API Manager > Credentials 我创造了 OAuth 2.0 client ID
    6. 已为项目启用Gmail API

    在Google Apps管理控制台中:

    1. 在里面 Security > Advanced Settings > Manage API client access 我已经添加了 Client ID 从步骤 4 在上面
    2. 我已经为添加了所有可能的作用域 客户端ID

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

    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 回复  |  直到 8 年前
        1
  •  17
  •   agoldis    8 年前

    所以我离解决方案只有一步之遥,问题是在创建 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云平台中创建项目
    2. 已创建服务帐户
    3. 启用 Domain Wide Delegation 服务帐户的
    4. 已下载JSON格式的服务帐户密钥
    5. API Manager > Credentials 我创造了 OAuth 2.0 Client ID
    6. 已为项目启用Gmail API

    在Google Apps管理控制台中:

    1. 在里面 Security > Advanced Settings > Manage API client access 我已经添加了 Client ID 从上面的步骤4开始
    2. 我已经为添加了所有可能的作用域 客户端ID

    这是发送邮件的代码:

    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);
         }
     });
    

    希望对别人有所帮助

        2
  •  0
  •   kamgman    4 年前

    非常感谢@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("=", "" );
    }