Reputation: 28837
gmail.users.labels.list()
functionality.When using Google's Node.js API I get a error trying to send a email. The error is:
{
"code": 403,
"errors": [{
"domain": "global",
"reason": "insufficientPermissions",
"message": "Insufficient Permission"
}]
}
fs.readFile(secretlocation, function processClientSecrets(err, content) {
if (err) {
console.log('Error loading client secret file: ' + err);
return;
}
authorize(JSON.parse(content), sendMessage);
});
function sendMessage(auth) {
var raw = makeBody('[email protected]', '[email protected]', 'subject', 'message test');
gmail.users.messages.send({
auth: auth,
userId: 'me',
message: {
raw: raw
}
}, function(err, response) {
res.send(err || response)
});
}
The function processClientSecrets
is from the Google guide i mentioned above. It reads my .json
file that has my access_token
and refresh_token
. The makeBody
function is a to make a encoded body message.
In the config variabels I have also:
var SCOPES = [
'https://mail.google.com/',
'https://www.googleapis.com/auth/gmail.modify',
'https://www.googleapis.com/auth/gmail.compose',
'https://www.googleapis.com/auth/gmail.send'
];
gmail.users.labels.list()
method.Is my setup wrong? Have there been changes in the API? What am I missing?
Upvotes: 25
Views: 27562
Reputation: 787
Also, I'd like to add something on top of the previous answers.
If you previously ran the examples with the gmail.readonly
scopes, make sure to delete the token.json
in order to redo the authentication with the new scopes.
Upvotes: 0
Reputation: 670
So for anyone looking at this trying to get a test email sent from their API but cant get this work heres what you gotta do:
Step 1: Replace the
var SCOPES = ['https://www.googleapis.com/auth/gmail.readonly'];
with this:
var SCOPES = [
'https://mail.google.com/',
'https://www.googleapis.com/auth/gmail.modify',
'https://www.googleapis.com/auth/gmail.compose',
'https://www.googleapis.com/auth/gmail.send'
];
Step 2: At the end of googles sample code add this:
function makeBody(to, from, subject, message) {
var str = ["Content-Type: text/plain; charset=\"UTF-8\"\n",
"MIME-Version: 1.0\n",
"Content-Transfer-Encoding: 7bit\n",
"to: ", to, "\n",
"from: ", from, "\n",
"subject: ", subject, "\n\n",
message
].join('');
var encodedMail = new Buffer(str).toString("base64").replace(/\+/g, '-').replace(/\//g, '_');
return encodedMail;
}
function sendMessage(auth) {
var raw = makeBody('[email protected]', '[email protected]', 'This is your subject', 'I got this working finally!!!');
const gmail = google.gmail({version: 'v1', auth});
gmail.users.messages.send({
auth: auth,
userId: 'me',
resource: {
raw: raw
}
}, function(err, response) {
return(err || response)
});
}
fs.readFile('credentials.json', function processClientSecrets(err, content) {
if (err) {
console.log('Error loading client secret file: ' + err);
return;
}
// Authorize a client with the loaded credentials, then call the
// Gmail API.
authorize(JSON.parse(content), sendMessage);
});
Step 3(Optional)
Delete this line:
authorize(JSON.parse(content), listLabels);
And these:
/**
* Lists the labels in the user's account.
*
* @param {google.auth.OAuth2} auth An authorized OAuth2 client.
*/
function listLabels(auth) {
const gmail = google.gmail({version: 'v1', auth});
gmail.users.labels.list({
userId: 'me',
}, (err, res) => {
if (err) return console.log('The API returned an error: ' + err);
const labels = res.data.labels;
if (labels.length) {
console.log('Labels:');
labels.forEach((label) => {
console.log(`- ${label.name}`);
});
} else {
console.log('No labels found.');
}
});
}
(So you don't get the random labels in your console)
Upvotes: 8
Reputation: 28837
Ok, so I found the problem(s).
Problem #1 While following the Node.js quickstart guide the example in that tutorial has
var SCOPES = ['https://www.googleapis.com/auth/gmail.readonly'];
And when I got the .json
that looks like:
{
"access_token": "xxx_a_long_secret_string_i_hided_xxx",
"token_type": "Bearer",
"refresh_token": "xxx_a_token_i_hided_xxx",
"expiry_date": 1451721044161
}
those tokens where produced taking into account only the auth/gmail.readonly
scope in the tutorial code.
So I deleted the first .json
, added the scopes from my final scope array (i posted in the question) and ran the tutorial setup again, receiving a new token.
Problem #2
In the object passed to the API I was sending:
{
auth: auth,
userId: 'me',
message: {
raw: raw
}
}
but that is wrong, message
key should be called resource
.
This is what I added to the tutorial's code:
function makeBody(to, from, subject, message) {
var str = ["Content-Type: text/plain; charset=\"UTF-8\"\n",
"MIME-Version: 1.0\n",
"Content-Transfer-Encoding: 7bit\n",
"to: ", to, "\n",
"from: ", from, "\n",
"subject: ", subject, "\n\n",
message
].join('');
var encodedMail = new Buffer(str).toString("base64").replace(/\+/g, '-').replace(/\//g, '_');
return encodedMail;
}
function sendMessage(auth) {
var raw = makeBody('[email protected]', '[email protected]', 'test subject', 'test message');
gmail.users.messages.send({
auth: auth,
userId: 'me',
resource: {
raw: raw
}
}, function(err, response) {
res.send(err || response)
});
}
And call everything with:
fs.readFile(secretlocation, function processClientSecrets(err, content) {
if (err) {
console.log('Error loading client secret file: ' + err);
return;
}
// Authorize a client with the loaded credentials, then call the
// Gmail API.
authorize(JSON.parse(content), sendMessage);
});
Upvotes: 31