Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
612 views
in Technique[技术] by (71.8m points)

node.js - Send mail via Google Apps Gmail using service account domain wide delegation in nodejs

I've been reading tutorials and seeing examples for 2 days already, with no success. I want to send an email using Google Apps Gmail account in NodeJS environment, however, i get 400 response from Google API:

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

Here's what I've done so far:

  1. Created a project in Google Cloud Platform
  2. Created a service account
  3. Enabled Domain Wide Delegation for the service account
  4. Downloaded the key for the service account in JSON format
  5. API Manager > Credentials i have created OAuth 2.0 client ID
  6. Enabled Gmail API for the project

In Google Apps Admin console:

  1. In Security > Advanced Settings > Manage API client access i have added the Client ID from step 4 above
  2. I have added all possible scopes for the Client ID

Here's the code that tries to send an email:

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: '[email protected]',
    message: {
      raw: raw
    }
  }, (err, res) => {
    if (err) {
      console.error(err);
    } else {
      console.log(res);
    }
});

I can see the Google auth success message and the request is sent with properly initialized token:

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 }

But still, the response is 400

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

So I was half-step close to the solution, the problem was that while creating const jwtClient = new google.auth.JWT(googleKey.client_email, null, googleKey.private_key, ['https://www.googleapis.com/auth/gmail.send'], null); i did not mention the account to be impersonated.

The correct initialization should be: const jwtClient = new google.auth.JWT(googleKey.client_email, null, googleKey.private_key, ['https://www.googleapis.com/auth/gmail.send'], '[email protected]');

To summarize, the correct steps are:

  1. Created a project in Google Cloud Platform
  2. Created a service account
  3. Enabled Domain Wide Delegation for the service account
  4. Downloaded the key for the service account in JSON format
  5. API Manager > Credentials i have created OAuth 2.0 Client ID
  6. Enabled Gmail API for the project

In Google Apps Admin console:

  1. In Security > Advanced Settings > Manage API client access i have added the Client ID from step 4 above
  2. I have added all possible scopes for the Client ID

This is the code that sends mails:

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

Hope that would be helpful for others


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...