gmail api auth issue - cannot get attachment from the chosen email - node.js

I'm working with node.js v13 with Gmail api.
I have done successfully getting the specific email message and now I'm trying
to get the attachment from that same email.
function getRecentEmail(auth) {
// Only get the recent email - 'maxResults' parameter
gmail.users.messages.list({ auth: auth, userId: 'me', maxResults: 1, q: 'subject:pokerrrr' }, function (
err,
response
) {
if (err) {
console.log('The API returned an error: ' + err);
return;
}
// Get the message id which we will need to retreive tha actual message next.
const message_id = response['data']['messages'][0]['id'];
// Retreive the actual message using the message id
gmail.users.messages.get({ auth: auth, userId: 'me', id: message_id }, function (err, response) {
if (err) {
console.log('The API returned an error: ' + err);
return;
}
// const attachment_id = response['data'].payload.parts[1].body.attachmentId;
const message = response['data'];
// getAttachments('me', message, auth);
const parts = message.payload.parts;
for (let i = 0; i < parts.length; i++) {
const part = parts[i];
if (part.filename && part.filename.length > 0) {
const attachId = part.body.attachmentId;
gmail.users.messages.attachments.get(
{
id: attachId,
messageId: message.id,
userId: 'me',
},
function (attachment) {
// saveAttachmentsToDir(part.filename, part.mimeType, attachment);
}
);
}
}
});
});
}
when I run the code above, the attachment parameter is showing me auth error and I cant understand why.
here is the error:
code:401
config:Object {url: "https://www.googleapis.com/gmail/v1/users/me/messa…", method: "GET", paramsSerializer: , …}
errors:Array(1) [Object]
message:"Login Required"
response:Object {config: Object, data: Object, headers: Object, …}
stack:"Error: Login Required
at Gaxios.<anonymous> (c:\Users\tomer\Desktop\Mail listener -tomer\Mail listener\node_modules\gaxios\build\src\gaxios.js:73:27)
at Generator.next (<anonymous>)
at fulfilled (c:\Users\tomer\Desktop\Mail listener -tomer\Mail listener\node_modules\gaxios\build\src\gaxios.js:16:58)
at processTicksAndRejections (internal/process/task_queues.js:97:5)"
__proto__:Error {constructor: }

Related

Send email from G-Suite in nodejs server using Gmail API returns 400 bad request

I want to send an email from my G-Suite account in a nodejs server using Gmail API.
I know the credentials are ok, cause I have no problem to get messages/labels from my G-Suite.
this is my code:
const {GoogleAuth} = require('google-auth-library');
async sendMessage(to, from, subject, message) {
let raw = makeBody(to, from, subject, message);
let url = `https://www.googleapis.com/gmail/v1/users/${<MyEmail>}/messages/send`
let option = {
method: 'POST',
headers: {
'Content-Type': 'message/rfc822',
},
body: raw,
};
let client = await getClient()
client.request({url, option}, (res, err) => {
if (err) {
console.log('error', err);
} else {
console.log('res');
}
});
}
async getClient() {
try {
let auth = new GoogleAuth({
credentials: {
client_email: <clientEmail>,
private_key: <privateKey>,
},
scopes: [
"https://mail.google.com/",
"https://www.googleapis.com/auth/gmail.compose",
"https://www.googleapis.com/auth/gmail.modify",
"https://www.googleapis.com/auth/gmail.send"],
clientOptions: {subject: <myEmail>}
});
const client = await auth.getClient();
if (client)
return client
} catch (e) {
console.log('error accured while getClient', e);
return e;
}
}
I added the scopes of send, compose and modify to Admin Google, unfortunately I get this 400 bad request:
error [
{
domain: 'global',
reason: 'invalidArgument',
message: 'Invalid id value'
}
]
Use googleapis library.
const {google} = require('googleapis');
const gmail = google.gmail('v1');
async sendMessage(to, from, subject, message) {
let raw = makeBody(to, from, subject, message);
let client = await auth.getClient()
google.options({
auth: client
});
const res = await gmail.users.messages.send({
userId: 'me',
requestBody: {
raw: raw,
},
});
}

Getting these errors on firebase cloud messaging

This is the error shown while using firebase messaging for push notifications...
Error: Exactly one of topic, token or condition is required
at FirebaseMessagingError.FirebaseError [as constructor] (/srv/node_modules/firebase-admin/lib/utils/error.js:42:28)
Error: Exactly one of topic, token or condition is required
at FirebaseMessagingError.FirebaseError [as constructor] (/srv/node_modules/firebase-admin/lib/utils/error.js:42:28)
at FirebaseMessagingError.PrefixedFirebaseError [as constructor] (/srv/node_modules/firebase-admin/lib/utils/error.js:88:28)
at new FirebaseMessagingError (/srv/node_modules/firebase-admin/lib/utils/error.js:254:16)
at Object.validateMessage (/srv/node_modules/firebase-admin/lib/messaging/messaging-types.js:46:15)
at Messaging.send (/srv/node_modules/firebase-admin/lib/messaging/messaging.js:208:27)
at sendNotification (/srv/index.js:227:18)
at exports.onCreateActivityFeedItem.functions.firestore.document.onCreate (/srv/index.js:197:13)
at <anonymous>
at process._tickDomainCallback (internal/process/next_tick.js:229:7)
This is the js code for firebase messaging
exports.onCreateActivityFeedItem = functions.firestore
.document('/feed/{userId}/feedItems/{activityFeedItem}')
.onCreate(async (snapshot, context) => {
console.log('Activity Feed Item Created', snapshot.data());
This log is printed...
// 1) Get user connected to the feed,
//send notification if they have token
const userId = context.params.userId;
const userRef = admin.firestore().doc(`users/${userId}`);
const doc = await userRef.get();
// 2) Once we have user check if they have notification item
const androidNotificationToken = doc.data().androidNotificationToken;
const createdActivityFeedItem = snapshot.data();
if (androidNotificationToken) {
// send notification
sendNotification(androidNotificationToken, createdActivityFeedItem);
} else {
console.log('User have no token, cant send notification');
}
function sendNotification(androidNotificationToken, activityFeedItem) {
let body;
// switch bod y value base on notification item (like, comment or follow)
switch (activityFeedItem.type) {
case 'comment':
body = `${activityFeedItem.username} replied: ${activityFeedItem.commentData}`;
break;
case 'like':
body = `${activityFeedItem.username} liked your post.`;
case 'follow':
body = `${activityFeedItem.username} followed you.`;
default:
break;
}
// 4) create message for push notification
const message = {
notification: { body },
token: { androidNotificationToken },
data: { recipient: userId }
};
// 5) send message with admin.messaging
admin
.messaging()
.send(message)
.then((response) => {
// Response is a message ID string.
console.log('Successfully sent message:', response);
})
.catch((error) => {
console.log('Error sending message:', error);
});
}
});
This is Flutter code
configurePushNotifications() {
final GoogleSignInAccount user = googleSignIn.currentUser;
if (Platform.isIOS) {
getIOSPermission();
}
_firebaseMessaging.getToken().then((token) {
print('Token received: $token');
usersRef.document(user.id).updateData({
'androidNotificationToken': token,
});
_firebaseMessaging.configure(
onMessage: (Map<String, dynamic> message) async {
print('Message is : $message');
final String recipientId = message['data']['recipient'];
final String body = message['notification']['body'];
if (recipientId == user.id) {
print('Notification Shown');
SnackBar snackbar = SnackBar(
content: Text(
body,
overflow: TextOverflow.ellipsis,
),
);
_scaffoldKey.currentState.showSnackBar(snackbar);
}
print('Notification not shown');
},
// onResume: (Map<String, dynamic> message) async {},
// onLaunch: (Map<String, dynamic> message) async {},
);
});
}
To get ios permission but i am using android phone for debugging
getIOSPermission() {
_firebaseMessaging.requestNotificationPermissions(
IosNotificationSettings(
alert: true,
badge: true,
sound: true,
),
);
_firebaseMessaging.onIosSettingsRegistered.listen((settings) {
print('Settings registered: $settings');
});
}
onCreateActivityFeedItem
Activity Feed Item Created { commentData: 'ab to man ja', mediaUrl: 'https://firebasestorage.googleapis.com/v0/b/chautari-ccfba.appspot.com/o/post_dcc8a054-a972-4b88-8d3f-4802de74393a.jpg?alt=media&token=1120cadb-14cb-4173-a4ec-775290f68fc8', postId: 'dcc8a054-a972-4b88-8d3f-4802de74393a', timeStamp: Timestamp { _seconds: 1589793598, _nanoseconds: 111000000 }, type: 'comment', userId: '116659062086341253410', userProfileImage: 'https://firebasestorage.googleapis.com/v0/b/chautari-ccfba.appspot.com/o/post_profile_pic_postId%3A116659062086341253410.jpg?alt=media&token=8da521ea-2a5e-4833-93b7-9a487afb7be5', username: 'rishi' }
3:23:55.242 PM
onCreateActivityFeedItem
Error: Exactly one of topic, token or condition is required
at FirebaseMessagingError.FirebaseError [as constructor] (/srv/node_modules/firebase-admin/lib/utils/error.js:42:28)
at FirebaseMessagingError.PrefixedFirebaseError [as constructor] (/srv/node_modules/firebase-admin/lib/utils/error.js:88:28)
at new FirebaseMessagingError (/srv/node_modules/firebase-admin/lib/utils/error.js:254:16)
at Object.validateMessage (/srv/node_modules/firebase-admin/lib/messaging/messaging-types.js:46:15)
at Messaging.send (/srv/node_modules/firebase-admin/lib/messaging/messaging.js:208:27)
at sendNotification (/srv/index.js:227:18)
at exports.onCreateActivityFeedItem.functions.firestore.document.onCreate (/srv/index.js:197:13)
at
at process._tickDomainCallback (internal/process/next_tick.js:229:7)
3:23:55.258 PM
onCreateActivityFeedItem
The error seems to come from the JavaScript code. More precisely, this seems off:
const message = {
notification: { body },
token: { androidNotificationToken },
data: { recipient: userId }
};
If you look at the Firebase documentation on sending a message it contains this example:
var message = {
data: {
score: '850',
time: '2:45'
},
token: registrationToken
};
You are wrapping the token in an extra {}, which is not correct as it leads to this JSON: token: { androidNotificationToken: "valueOfandroidNotificationToken" }.
More likely it needs to be:
const message = {
notification: { body },
token: androidNotificationToken,
data: { recipient: userId }
};

Firebase cloud function http sending push notification to device successfully but it falls into the catch block with empty error

Firebase cloud function HTTP send a push notification to device,
notification is sending successfully but it falls into the catch
block with an empty error instead of response block
here's my index.js code:
exports.test = functions.https.onRequest((request, response) => {
var missingData = [];
var tokenPass = request.query.token_passed ? request.query.token_passed : missingData.push({
key : 'token',
message : "Token cannot be null"
});
if (missingData.length > 0) {
response.status(403);
responseData = {
status : 403,
success : false,
message : "Missing data input",
data : missingData
}
response.send(responseData);
return;
}
const payload = {
notification: {
title: 'Hi',
body: 'Body'
}
};
// Send a message to the device corresponding to the provided
// registration token.
admin.messaging().sendToDevice(tokenPass, payload)
.then((response) => {
response.status(200);
response.send({
status : 200,
success : true,
message : "send notification successful"
});
return;
})
.catch((error) => {
response.status(500);
response.send({
status : 500,
success : false,
err: error,
message : "internal error"
});
return;
});
});
Here's the response which I get:
{
"status": 500,
"success": false,
"err": {},
"message": "internal error"
}
I tried doing like this too, but no success:
var message = {
notification: {
title: titlePass,
body: bodyPass
},
token: tokenPass
};
// Send a message to the device corresponding to the provided
// registration token.
admin.messaging().send(message)
P.S. I added the stripe module to my firebase functions, could it be causing issues?

Update user using google admin directory api returns 200 but does not update. Malformed request body?

I have a user in my google admin console with the email dog#jopfre.com.
I can auth successfully and add and delete users using the api.
Now I am trying to update the user using the api.
Here is a simplified version of my code:
const admin = google.admin({version: 'directory_v1', auth});
admin.users.update({
userKey: "dog#jopfre.com",
requestBody: {
primaryEmail: "cat#jopfre.com"
}
},(err, data) => {
console.log(err || data);
});
This returns json of the request and a 200 status.
The nearest example I can find in the docs is this:
admin.members.insert({
groupKey: 'my_group#example.com',
requestBody: { email: 'me#example.com' },
auth: jwt
}, (err, data) => {
console.log(err || data);
});
So it looks pretty similar to me.
I have tried with and without quotation marks on the requestBody key and have also tried updating different key values like givenName and suspended. I'm guessing my request is malformed somehow but I can't work out how as no error is returned.
Any clue or ideas of what to try next?
Here are some of the more relevant lines from the returned json:
status: 200,
params: { requestBody: { primaryEmail: 'cat#jopfre.com' } },
_hasBody: true,
header: 'PUT /admin/directory/v1/users/dog#jopfre.com?requestBody%5BprimaryEmail%5D=cat%40jopfre.com HTTP/1.1\r\nAccept: application/json, text/plain, */*\r\nContent-Type: application/x-www-form-urlencoded\r\nAuthorization: Bearer ya29.GlwXBi796knRrOTbzvJ1ihzBaQqHKk3HYA9-3pxUgCxaCvPKxZLYGRrghq_RcFHbZYqyKEqUV6yOWusBui2Vh1DLd50MsKQ5o4MoqzutVr8P280ULY2cYzSYLtGOyw\r\nUser-Agent: google-api-nodejs-client/1.6.1\r\nHost: www.googleapis.com\r\nConnection: close\r\nContent-Length: 0\r\n\r\n',
path: '/admin/directory/v1/users/dog#jopfre.com?requestBody%5BprimaryEmail%5D=cat%40jopfre.com',
responseUrl: 'https://www.googleapis.com/admin/directory/v1/users/dog#jopfre.com?requestBody%5BprimaryEmail%5D=cat%40jopfre.com',
_requestBodyLength: 0,
Not sure if the requestBodyLength should be 0, that seems off.
Using resource instead of requestBody works in v33.0.0 of googleapis.
const admin = google.admin({version: 'directory_v1', auth});
admin.users.update({
userKey: "dog#jopfre.com",
resource: {
primaryEmail: "cat#jopfre.com"
}
},(err, data) => {
console.log(err || data);
});
Effective release of googleapis version 30.0.0 resource and requestBody are equally accepted.
Below are working examples for users.insert, users.list, users.update, users.get and users.delete functions, all tested with googleapis version 30.0.0
async function insertUser(auth) {
const service = google.admin({version: 'directory_v1', auth});
console.log("Inserting user");
const response = await service.users.insert({
"requestBody":{
"name": {
"familyName": "Friends",
"givenName": "John Smith",
},
"password": "**********",
"primaryEmail": "j.smith#jopfre.com",
}
})
// Log the results here.
console.log(`status: ${response.status}\nprimary email: ${response.data.primaryEmail}\nupdated familyName: ${response.data.name.fullName}`)
console.log("\n"); // insert a line break.
}
async function listUsers(auth) {
console.log('Listing users')
const service = google.admin({version: 'directory_v1', auth});
const response = await service.users.list({
customer: 'my_customer',
maxResults: 150,
orderBy: 'email',
})
const users = response.data.users;
if (users.length) {
console.log('Users:');
users.forEach((user) => {
console.log(`${user.primaryEmail} -(${user.name.fullName})`);
});
} else {
console.log('No users found.');
}
console.log("\n"); // insert a line break.
}
async function updateUserInfo(auth) {
console.log('Updating user info')
const service = google.admin({version: 'directory_v1', auth});
const response = await service.users.update({
"userKey": "j.smith#jopfre.com",
"requestBody": {
"name": {
"familyName": "Work"
},
"primaryEmail": "john.smith#jopfre.com"
}
})
// Log the results here.
console.log('User info is updated successfully')
console.log(`status: ${response.status}, prime email: ${response.data.primaryEmail} updated familyName: ${response.data.name.familyName}`)
for (i = 0; i < response.data.emails.length; i++) {
console.log(`address: ${response.data.emails[i]["address"]}`)
}
console.log("\n"); // insert a line break.
}
async function getUserMeta(auth) {
console.log('Getting user info')
const service = google.admin({version: 'directory_v1', auth});
const response = await service.users.get({
"userKey" : "j.smith#jopfre.com"
})
console.log('User info is obtained successfully')
console.log(`primary email: ${response.primaryEmail}, full name: ${response.data.name.fullName}`)
console.log("\n"); // insert a line break.
}
async function deleteUser(auth) {
console.log('Deleting user')
const service = google.admin({version: 'directory_v1', auth});
const response = await service.users.delete({
"userKey" : "j.smith#jopfre.com"
})
if (response.data == "") {
console.log("User is deleted successfully");
}
}

Push notification returns ECONNRESET in Google Cloud Functions

I am having a function in Firebase Cloud Functions that is retrieves the user's device group id in order to send a push notification, and after sends a push notification. This works well if the function gets called only once, but if I have an array of users I want to send a push notification too, the sendPushNotification function returns error : FAILED err= { RequestError: Error: read ECONNRESET
at new RequestError (/user_code/node_modules/request-promise/node_modules/request-promise-core/lib/errors.js:14:15) for every try to send push
From what i understand ECONNRESET means that the connection gets closed at one end before finishing the operation, can some help/explain me why this is:
here is my code:
function sendFollowNotification(snapshot) {
const notificationMsg = getFollowNotificationMsg() //returns a string
snapshot.forEach(function(singleUser, index) {
const userId = singleUser.key;
const userObject = singleUser.val();
console.log("will get device group")
if (index + 1 == snapshot.numChildren()) {
return getDeviceGroupNotificationKey(userId, "Discover new artists", notificationMsg, "", true);
} else {
getDeviceGroupNotificationKey(userId, "Discover new artists", notificationMsg, "", false);
}
}
function getDeviceGroupNotificationKey(groupId, notificationTitle, notificationBody, notificationSubject, shouldReturn) {
const pathToDeviceGroup = admin.database().ref('deviceGroups').child(groupId);
pathToDeviceGroup.once("value").then( function(snapshot) {
const deviceGroupObj = snapshot.val();
const notification_key = deviceGroupObj.notification_key;
console.log("got notification key")
console.log(notification_key)
if (notification_key !== undefined) {
return sendPushToDeviceGroupOld(notification_key, notificationTitle, notificationBody, "notificationKeyOld2", notificationSubject, shouldReturn);
} else {
return
}
}).catch(reason => {
console.log("user device group not there")
return
})
}
function sendPushToDeviceGroupOld(notification_key, title, body, subject, message, shouldReturn) {
console.log('sending push to ' + notification_key)
const serverKey = '-';
const senderId = '-';
const options = {
method: 'POST',
uri: 'https://fcm.googleapis.com/fcm/send',
headers: {
'Authorization': 'key=' + serverKey,
'project_id': senderId
},
body: {
to: notification_key,
data: {
subject: message
},
notification: {
title: title,
body: body,
badge: 1,
sound: "default",
},
priority : 'high',
content_available: true
},
json: true
};
return rqstProm(options)
.then((parsedBody) => {
console.log('SUCCESS response=', parsedBody);
return
})
.catch((err) => {
console.log('FAILED', err);
return
});
}

Resources