question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Failed sending mail with service account and JWT auth

See original GitHub issue

I’m trying to send an email using a service account and JWT authentication and keep getting and error with a very unhelpful message: { code: 500, message: null }

This code snippet is from the following StackOverflow link: http://stackoverflow.com/questions/25207217/failed-sending-mail-through-google-api-in-nodejs

It seems like the solution there was to change the key in the parameters to resource instead of message but it’s not working for me. This is strange because in the JS example in the docs (https://developers.google.com/gmail/api/v1/reference/users/messages/send) it claims the key is still message

I’m authenticating with

var jwtClient = new google.auth.JWT(config.SERVICE_EMAIL, config.SERVICE_KEY_PATH, null, config.ALLOWED_SCOPES);

then sending an email with

jwtClient.authorize(function(err, res) {
  if (err) return console.log('err', err);

  var email_lines = [];

  email_lines.push("From: \"Some Name Here\" <rootyadaim@gmail.com>");
  email_lines.push("To: hanochg@gmail.com");
  email_lines.push('Content-type: text/html;charset=iso-8859-1');
  email_lines.push('MIME-Version: 1.0');
  email_lines.push("Subject: New future subject here");
  email_lines.push("");
  email_lines.push("And the body text goes here");
  email_lines.push("<b>And the bold text goes here</b>");

  var email = email_lines.join("\r\n").trim();

  var base64EncodedEmailSafe = new Buffer(email).toString('base64').replace(/\+/g, '-').replace(/\//g, '_');

  var params = {
    auth: jwtClient,
    userId: "myaddress@gmail.com",
    resource: {
      raw: base64EncodedEmailSafe
    }
  };

  gmail.users.messages.send(params, function(err, res) {
    if (err) console.log('error sending mail', err);
    else console.log('great success', res);
  });
}

What am I missing?

Issue Analytics

  • State:closed
  • Created 9 years ago
  • Comments:15 (5 by maintainers)

github_iconTop GitHub Comments

7reactions
stken2050commented, Feb 18, 2017

Sort of surprised to have found my own post about this issue having the same trouble and googling for my other project after years.

@kunokdev Yes. We need to set “subject (or sub) field” of google.auth.JWT which should be identical to a gmail address to be managed. This is rarely explained for g-suite/gmail API, and an only document I could find is:

https://developers.google.com/identity/protocols/OAuth2ServiceAccount

Additional claims

In some enterprise cases, an application can request permission to act on behalf of a particular user in an organization. Permission to perform this type of impersonation must be granted before an application can impersonate a user, and is usually handled by a domain administrator. For more information on domain administration, see Managing API client access.

To obtain an access token that grants an application delegated access to a resource, include the email address of the user in the JWT claim set as the value of the sub field.

Unfortunately, this field does not accept array, so to manage multiple gmail address under the same domain, you need to obtain each jwtClients.

After all, a single service account with a single credential works for multiple gmail addresses under the same domain.

https://developers.google.com/admin-sdk/directory/v1/guides/delegation

Here is a very clean node.js sample to get started.

(() => {
  "use strict";
  //============================
  const google = require('googleapis');
  const google_key = require("/your/google-key.json"); //download from google API console

  const jwtClient = new google.auth.JWT(
    google_key.client_email,
    null,
    google_key.private_key,
    ["https://mail.google.com/"], //full access for now, you can restrict more
    'adm@yourdomain.com' // subject (or sub) <-----------------------
  );

  jwtClient.authorize((err, tokens) => (err
    ? console.log(err)
    : (() => { //--------------------------------
      console.log("Google-API Authed!");
      const gmail = google.gmail({
        version: "v1",
        auth: jwtClient
      });
      gmail.users.messages.list({
        userId: 'adm@yourdomain.com'
      }, (err, messages) => {
        //will print out an array of messages plus the next page token
        console.log(err);
        console.dir(messages);
      });
    })() //--------------------------------
  //======================
  ));
//============================
})();

3reactions
ryanseyscommented, Jan 13, 2015

Ah, right. You cannot authorize Gmail API requests with JWT, you must use OAuth 2.0 because it needs to be auth’d to a specific user. Or else you’d be able to do some really shady things like send messages impersonating someone else. The Google APIs Explorer is authenticated with OAuth 2.0 that’s why it works. See https://developers.google.com/gmail/api/auth/about-auth for more information.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Failed sending mail with googleapis' service account and JWT ...
I'm trying to send an email using a service account and JWT authentication and keep getting and error with a very unhelpful message:...
Read more >
Using OAuth 2.0 for Server to Server Applications | Authorization
The JWT assertion is signed with a private key not associated with the service account identified by the client email or the key...
Read more >
Authentication between services - Google Cloud
Creates a JWT and signs it with the service account's private key. Sends the signed JWT in a request to the API. ESP...
Read more >
Using Gmail/GSuite SMTP OAUTH with Service Account
To access user data in G Suite, you must get authorization from G Suite administrator.
Read more >
General Administration and Authentication - DocuSign Support
Support will send an envelope requesting authorization, and once that is ... This error indicates the User ID and Account ID in your...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found