3

I'm trying to using Google's API to send an email. I have a web application powered by AngularJS where the user signs in with their google account (via passport.js) using oauth2. A new access token is written to their account on my database. Their google user ID is also written to their account. I'd like the user to be able to send an email via an HTTP request using simply their user Id and access token. I'm using Postman to make some test requests, but I keep getting this error:

{
  "error": {
    "errors": [
      {
        "domain": "global",
        "reason": "insufficientPermissions",
        "message": "Insufficient Permission"
      }
    ],
    "code": 403,
    "message": "Insufficient Permission"
  }
}

I'm using the following link to make a POST request:

https://content.googleapis.com/gmail/v1/users/106xxxxxxxxxxx/messages/send

In my header, I have:

Authorization: Bearer yaxx._wxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Content-Type: application/json

My body:

{
 "raw": "test"
}

I've had some of the emails intermittently come in using this method, but I can't seem to recreate a successful request with certainty. I'm a little confused by Google's documentation. Do I need to explicitly grant access as seen in the example at the bottom of this page?

mjoyce91
  • 316
  • 2
  • 19

1 Answers1

4

The access token you mentioned needs to be present in the POST-request you send the mail with. The Oauth2-procotol dictates that you need to either pass along a header Authorization: Bearer <ACCESS_TOKEN>, or a parameter access_token=<ACCESS_TOKEN>.

The value of raw also needs to be a valid base64-encoded rfc822 mail. An example in JavaScript could look like the following:

// Base64-encode the mail and make it URL-safe 
// (replace all "+" with "-" and all "/" with "_")
var encodedMail = btoa(
      "Content-Type: text/plain; charset=\"UTF-8\"\n" +
      "MIME-Version: 1.0\n" +
      "Content-Transfer-Encoding: 7bit\n" +
      "Subject: Subject of the mail\n" +
      "From: sender@gmail.com\n" +
      "To: reciever@gmail.com\n\n" +

      "This is where the mail text will go"
    ).replace(/\+/g, '-').replace(/\//g, '_');

This will result in a string that you use as the raw in the request body.

A request in Postman would then look like the following:

POST https://www.googleapis.com/gmail/v1/users/me/messages/send?access_token=<ACCESS_TOKEN>

{ // The encoded mail from the example above.
 "raw": "Q29udGVudC1UeXBlOiB0ZXh0L3BsYWluOyBjaGFyc2V0PSJVVEYtOCIKTUlNRS1WZXJzaW9uOiAxLjAKQ29udGVudC1UcmFuc2Zlci1FbmNvZGluZzogN2JpdApTdWJqZWN0OiBTdWJqZWN0IG9mIHRoZSBtYWlsCkZyb206IHNlbmRlckBnbWFpbC5jb20KVG86IHJlY2lldmVyQGdtYWlsLmNvbQoKVGhpcyBpcyB3aGVyZSB0aGUgbWFpbCB0ZXh0IHdpbGwgZ28="
}

You also need to supply the Content-Type-header with the value of application/json. Note that you don't have to use a userId. Supplying me will make Google use the user associated with the supplied access token automatically.

Also make sure you asked for a sufficient permission scope with Passport. https://mail.google.com/ will work.

Community
  • 1
  • 1
Tholle
  • 108,070
  • 19
  • 198
  • 189
  • Thanks, but I'm getting the same error response. Here's a copy of my Postman HTTP request. `POST /gmail/v1/users/me/messages/send?access_token=ya29.xxxxxxxxxxxxxxxxx HTTP/1.1 Host: www.googleapis.com Content-Type: application/json Cache-Control: no-cache Postman-Token: c152b250-b38f-7280-6466-xxxxxxxxxxxxxx { "raw": "Q29udGVudC1UeXBlOiB0ZXh0L3BsYWluOyBjaGFyc2V0PSJVVEYtOCIKTUlNRS1WZXJzaW9uOiAxLjAKQ29udGVudC1UcmFuc2Zlci1FbmNvZGluZzogN2JpdApTdWJqZWN0OiBTdWJqZWN0IG9mIHRoZSBtYWlsCkZyb206IHNlbmRlckBnbWFpbC5jb20KVG86IHJlY2lldmVyQGdtYWlsLmNvbQoKVGhpcyBpcyB3aGVyZSB0aGUgbWFpbCB0ZXh0IHdpbGwgZ28=" }` – mjoyce91 Oct 01 '15 at 18:22
  • @MikeJoyce Updated the answer :) – Tholle Oct 01 '15 at 18:30
  • @Throlle : Your answer works for me but I would like to know From where did you get these different fields. I could not find it even in GMail API documentation – Wael Showair Oct 02 '15 at 01:28
  • @WaelShowair The needed scope and that the raw-field has to be a url-safe base64-encoded string is stated in the gmail-api docs. Where the access token should be placed is a oauth2-convention. I found this out on various SO-questioms, though. – Tholle Oct 02 '15 at 04:38
  • @Tholle : So this gets more at the heart of my question - can the scope be placed in the same HTTP request? Literally looking to be able to do this from postman without explicitly giving permission to an app. – mjoyce91 Oct 02 '15 at 12:30
  • @MikeJoyce Sadly, no. The scopes have to be given at the time you redirect the user to Google at the same time you give your ClientId and Secret. This will then give you a code you exchange for the access token used above. There is no way around this. – Tholle Oct 02 '15 at 12:31
  • Ah okay. Thanks for your help! Accepting your answer because it will still help me implement what I'm trying to do. – mjoyce91 Oct 02 '15 at 12:41
  • @MikeJoyce Sweet :) Good luck! – Tholle Oct 02 '15 at 12:42