Gmail API using nodejs, asnyc function to get messages - javascript

I've been trying to make this work but couldn't figure it out.
I need to retrieve all the mail id's then get those mail messages using their ids. Because it's not async, when exporting the data I get nothing.
function listMessages(auth) {
const gmail = google.gmail({version: 'v1', auth});
let data;
gmail.users.messages.list({
'userId': 'mail address',
'q': 'some query'
}, (err, res) => {
res.data.messages.forEach(element => {
console.log(element);
mails.push(element.id);
});
mails.forEach((id) => {
request = gmail.users.messages.get({
'userId': 'sedatcyalcin#gmail.com',
'id': id
}, (err, res) => {
data = res.data.snippet;
console.log(data);
});
})
});
}
I can export mails but can't export data;

This is how I made it work:
function getRecentEmail(auth) {
const gmail = google.gmail({ version: 'v1', auth });
// Only get the recent email - 'maxResults' parameter
gmail.users.messages.list({ auth: auth, userId: 'me', maxResults: 1, }, 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.
var 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;
}
email = response.data
console.log(email)
});
}); }
And I called it in your index.js file below this line:
// Authorize a client with credentials, then call the Gmail API.
authorize(JSON.parse(content), getRecentEmail);

Maybe dividing into 2 functions and if the one returns promise may solve it.
const listMessages = auth => {
return new Promise((resolve , reject)=>{
const gmail = google.gmail({version: 'v1', auth});
let data;
gmail.users.messages.list({
'userId': 'mail address',
'q': 'some query'
}, (err, res) => {
res.data.messages.forEach(element => {
console.log(element);
mails.push(element.id);
resolve(mails)
});
})
})
}
const getMessages = () => {
listMessages().then(mails=>{
mails.forEach((id) => {
request = gmail.users.messages.get({
'userId': 'sedatcyalcin#gmail.com',
'id': id
}, (err, res) => {
data = res.data.snippet;
console.log(data);
});
})
})
}
Birde boyle dene , olmaz ise sorunu daha detaylı anlatırsan yardım etmeye çalışırım.

Here is my TS based solution to list messages.
Note that format: 'raw' returns base64. Remove that line if you just want snippets of each email that matches your query.
const gmail = google.gmail({ version: 'v1', auth });
let data: string | undefined;
const mails: string[] = [];
gmail.users.messages?.list(
{
userId: 'me',
q: 'from: some query',
maxResults: 1,
},
(err, res) => {
if (!res || !res.data || !res.data.messages) {
console.log('No Messages Found');
return;
}
res.data.messages.forEach((message) => {
console.log(`first api call: ${message}`);
mails.push(message.id ?? '');
});
mails.forEach((id) => {
const req = gmail.users.messages.get(
{
userId: 'me',
id,
format: 'raw',
},
(err, res) => {
// data = res?.data.snippet!;
console.log(res?.data);
}
);
});
}
);
};

Related

Use switch case in node.js

I want to implement switch case for registration flow. Like normal sign up with
email, Phone number and password
with google
with facebook etc.
If user selects the continue with google button then switch to google registration and so on. How can I do that?
The controller file:
exports.register = catchAsync(async (req, res, error) => {
try {
const user = await userService.googleRegistration(req);
} catch (error) {
return res.failed(500, "Internal server error", error);
}
});
The userService file:
// GOOGLE REGISTRATION
exports.googleRegistration = async (req) => {
var google = require("googleapis").google;
var OAuth2 = google.auth.OAuth2;
var oauth2Client = new OAuth2();
oauth2Client.setCredentials({ access_token: req.params.access_token });
var oauth2 = google.oauth2({
auth: oauth2Client,
version: "v2",
});
oauth2.userinfo.get(async (err, res) => {
if (err) {
} else {
let user_data = new User({
first_name: res.data.given_name,
last_name: res.data.family_name,
});
let user = await user_data.save();
return user;
}
});
};
// NORMAL REGISTRATION
exports.register = async (user) => {
let new_user = new User({ ...user });
const user_data = await new_user.save();
const payload = { id: new_user._id };
user_data.JWToken = jwt.sign(payload, keys.JWToken, { expiresIn: 31556926 });
return user_data;
};
I recomended use an des-structuct object. NOT recomended use a switch it is bad for the memory and performance
const typeSingIn = {
facebook: function(){ /* function to join with fb */},
google: function() {/* your function to join with google*/},
// more options
}
app.post("/singIn", (req, res) => {
const {method} = req.body // expect the answer if the signIn is for fb, google or other method.
const singInType = typeSignIn[method]
try{
signInType() // this can be a promise if you want it
}catch(e){
res.json({status: 500, message: e})
}
})

Getting erros using passport-google-oauth20 InternalOAuthError: Failed to fetch user profile and Cannot set headers after they are sent to the client

I'm using passport strategies for different socialMedia logins and getting the following two errors
InternalOAuthError: Failed to fetch user profile
Cannot set headers after they are sent to the client
I have doubt there somewhere I have returned a callback or response so getting 2nd error but for 1st don't know reasons scope seems to be correct!
strategy code
passport.use(new GoogleStrategy({
clientID: GOOGLE_CLIENT_ID,
clientSecret: GOOGLE_SECRET_KEY,
callbackURL: GOOGLE_CALLBACK_URL
}, async (acessToken, refreshToken, profile, done) => {
await User.findOne({ email: profile._json.email }, async (err, user) => {
if (err) {
console.log("passport.config --> err", err);
done(err, null);
} else if (user) {
if (user.socialType !== "GOOGLE" || user.socialType === null)
done(`LOGIN_CREDENTIALS_WITH_${(user.socialType || "PASSWORD").toUpperCase()}`, false);
else {
done(null, user);
}
} else {
// console.log(profile);
const user = {
email: profile._json.email,
socialId: profile.id,
socialType: "GOOGLE",
firstName: profile.name.givenName,
lastName: profile.name.familyName,
isActive: profile._json.email_verified,
isVerified: profile._json.email_verified,
socialImageUrl: profile._json.picture,
userType: "CUSTOMER"
};
const newUser = new User({ ...user });
const newUserData = await newUser.save();
done(null, newUserData);
}
});
}));
route code:
router.get('/auth/:socialType', customerCtrl.socialTypeLogin);
router.get('/auth/:socialType/callback', customerCtrl.socialTypeLoginCallback);
controller code:
const socialTypeLogin = async (req, res) => {
await customerService.socialTypeLogin(req, res);
};
const socialTypeLoginCallback = async (req,res) => {
await customerService.socialTypeLoginCallback(req,res);
};
service code:
const socialTypeLogin = async (req, res) => {
try {
const socialType = (req.params.socialType || '').toLowerCase();
const GOOGLE_SCOPE = ['email', 'profile'];
const FACEBOOK_SCOPE = ['email'];
let scope = [];
if (socialType === 'google') {
scope = GOOGLE_SCOPE;
} else if (socialType === 'facebook') {
scope = FACEBOOK_SCOPE;
}
let oauthOptions = { scope: scope};
const { returnUrl } = req.query;
if(returnUrl && returnUrl.trim().length !== 0) {
oauthOptions['state'] =JSON.stringify({ returnUrl: returnUrl });
}
passport.authenticate(socialType, oauthOptions)(req, res);
}
catch (error) {
}
}
/**
* #param {string} socialType
*/
const socialTypeLoginCallback = async (req, res) => {
const socialType = (req.params.socialType || '').toLowerCase();
// return new Promise((resolve, reject) => {
try {
passport.authenticate(socialType, async (err, user) => {
let webappRedirectURL = WEBAPP_LOGIN_URL;
try {
const state = req.query.state;
if(state) {
const stateObj = JSON.parse(state);
webappRedirectURL = stateObj.returnUrl;
}
} catch (err1) {
console.log("customer.service --> parsing error",err1);
}
if (err || !user) {
console.log("customer.service --> !user",err);
res.render('oauth-redirect', {
webappRedirectURL: webappRedirectURL,
success: false,
error: err,
timerCounter: 5,
accessToken: undefined
});
}
else {
console.log("customer.service --> Generating Token",user.generateJWT());
res.render('oauth-redirect', {
webappRedirectURL: webappRedirectURL,
success: true,
timerCounter: 5,
accessToken: user.generateJWT(),
error: undefined
});
}
})(req, res);
}
catch (error) {
console.log("customerService.js ==> socialTypeLoginCallback -->",error);
}
};
Thanks for help in advance!
I have doubt there somewhere I have returned a callback or response so getting 2nd error but for 1st don't know reasons scope seems to be correct!
In socialTypeLogin
add line
oauthOptions['session'] = false;

my homepage wont render using my google oauth

This is the error that I get:
"You have created a new client application that use…i/web/guides/gis-migration) for more information."
here are my codes on server, the statement inside console.log doesnt even show:
static async googleLogin(req, res, next) {
try {
console.log("masuk google login server")
const { id_token } = req.body
const client = new OAuth2Client(process.env.GOOGLE_CLIENT_ID)
const ticket = await client.verifyIdToken({
idToken: id_token,
audience: process.env.GOOGLE_CLIENT_ID
});
const payload = ticket.getPayload()
const email = payload.email
let password = email.toString().split('#')
password = password[0]
let user = await User.findOne({ where: { email } })
if (!user) {
let newUser = { email, password }
let createUser = await User.create(newUser)
const payload = {
id: createUser.id,
email: createUser.email
}
const access_token = generateToken(payload)
return res.status(201).json({ access_token })
} else {
const payload = {
id: user.id,
email: user.email
}
const access_token = generateToken(payload)
return res.status(200).json({ access_token })
}
} catch (err) {
console.log(err)
return next(err)
}
}
the console.log in my client also doesnt show
function onSignIn(googleUser) {
console.log("masuk client oauth")
$.ajax({
method: "POST",
url: `${baseUrl}/users/google-login`,
data: {
id_token: googleUser.getAuthResponse().id_token
}
})
.done((response) => {
console.log(response, "client response")
localStorage.setItem("access_token", response.access_token)
checkLocalStorage();
})
.fail((err) => {
console.log(err, "error client");
})
.always(() => {
authentication()
})
}
i tried deleting cache and run my app again, recreate a new project on google api (which genereated new ID). they didnt work

Async await on Nodejs API call

I'm trying to execute a function after another function (API call) has returned its result. The problem is, the program always ends up executing the second one before the first one has given the result.
The thing is, I need to place a contact email on a Mailing List using Mailjet, but first I have to create that contact. So, the contact creation works, but not the placement on the list, as this function is executed before the contact creation finishes.
I tried multiple things for some days, mostly using async/await, but I still don't get my head around it.
Here's my code:
routes/index.js
router.post('/', async (req, res, next) => {
const { email, name } = req.body;
const mktListId = process.env.MAILJET_ID_MARKETING;
try {
const contactCreated = await createContact(email, name);
addEmailToList(email, mktListId);
res.status(201).send({ message: 'Email Successfully subscribed to Marketing List' });
} catch (err) {
res.status(400).json({
status: 'fail',
message: err,
});
}
});
function createContact(email, name) {
const mailjet = require('node-mailjet').connect(
process.env.MAILJET_MASTER_APIPUBLIC,
process.env.MAILJET_MASTER_APISECRET
);
const request = mailjet.post('contact', { version: 'v3' }).request({
IsExcludedFromCampaigns: 'true',
Name: `${name}`,
Email: `${email}`,
});
request
.then(result => {
console.log('result mailjet create contact', result.body);
})
.catch(err => {
console.log('error mailjet create contact', err.statusCode, err.ErrorMessage);
});
}
function addEmailToList(email, listId) {
const mailjet = require('node-mailjet').connect(
process.env.MAILJET_MASTER_APIPUBLIC,
process.env.MAILJET_MASTER_APISECRET
);
const request = mailjet.post('listrecipient', { version: 'v3' }).request({
IsUnsubscribed: 'true',
ContactAlt: `${email}`,
ListID: `${listId}`,
});
request
.then(result => {
console.log('result mailjet add to list', result.body);
})
.catch(err => {
console.log('error mailjet add to list', err.statusCode, err.ErrorMessage);
});
}
Any help with be much appreciated. Thank you!
Without a promise, await doesn't really do anything.
await new Promise (resolve => {
console.log ("A");
resolve ();
});
await new Promise (resolve => {
console.log ("B");
resolve ();
});
await new Promise (resolve => {
console.log ("C");
resolve ();
});
The create function needs to look more like:
function createContact(email, name) {
return new Promise ((resolve, reject) => {
const mailjet = require('node-mailjet').connect(
process.env.MAILJET_MASTER_APIPUBLIC,
process.env.MAILJET_MASTER_APISECRET
);
const request = mailjet.post('contact', { version: 'v3' }).request({
IsExcludedFromCampaigns: 'true',
Name: `${name}`,
Email: `${email}`,
});
request
.then(result => {
console.log('result mailjet create contact', result.body);
resolve ();
})
.catch(err => {
console.log('error mailjet create contact', err.statusCode, err.ErrorMessage);
reject ();
});
});
}
For future reference, this is the clean finished and refactored code:
routes/index.js
const express = require('express');
const router = express.Router();
const emailController = require('../controllers/emailController');
router.post('/', subscriberValidationRules(), validate, emailController.create);
Then we put the router logic on:
controllers/emailController.js
const { createContact, addEmailToList } = require('../helpers/addEmailToList');
const create = async (req, res, next) => {
const { email, name } = req.body;
const mktListId = process.env.MAILJET_ID_MARKETING;
try {
await createContact(email, name);
await addEmailToList(email, mktListId);
return res.status(201).send({ message: 'Email Successfully subscribed to Marketing List' });
} catch (err) {
res.status(400).json({
status: 'fail',
message: err,
});
}
}
module.exports = {
create,
};
And then our functions on:
helpers/addEmailToList.js
const createContact = async (email, name) => {
try {
const mailjet = require('node-mailjet').connect(
process.env.MAILJET_MASTER_APIPUBLIC,
process.env.MAILJET_MASTER_APISECRET,
)
const { body } = await mailjet.post('contact', { version: 'v3' }).request({
IsExcludedFromCampaigns: 'true',
Name: `${name}`,
Email: `${email}`,
})
console.info('result mailjet create contact', body)
return body
} catch (err) {
console.info('error mailjet create contact', err.statusCode, err.ErrorMessage)
}
}
const addEmailToList = async (email, listId) => {
const mailjet = require('node-mailjet').connect(
process.env.MAILJET_MASTER_APIPUBLIC,
process.env.MAILJET_MASTER_APISECRET
);
try {
const { body } = await mailjet.post('listrecipient', { version: 'v3' }).request({
IsUnsubscribed: 'true',
ContactAlt: `${email}`,
ListID: `${listId}`,
});
console.info('result mailjet add to list', body);
return body;
} catch (err) {
console.info('error mailjet add to list', err.statusCode, err.ErrorMessage);
}
};
module.exports = {
createContact,
addEmailToList,
};

Request_BadRequest in O365

I am trying to send a email with the help of O365. I have configured everything but I am getting a error
GraphError { statusCode: 405, code: 'Request_BadRequest',
message: 'Specified HTTP method is not allowed for the request
target.', requestId: '34f321-57de-4483-b97d-5957f8786ecb', date:
2019-09-16T00:17:53.000Z, body:
'{"code":"Request_BadRequest","message":"Specified HTTP method is not
allowed for the request
target.","innerError":{"request-id":"34f803b1-57de-4483-b97d-5957f8786ecb","date":"2019-09-16T05:47:51"}}'
}
Code
const APP_ID = "XXXXXXXXXXXXXXXXXX";
const APP_SECERET = "XXXXXXXXXXXXXX";
const TENANT_ID = "XXXXXXXXXXXXXXXX";
const TOKEN_ENDPOINT = "https://login.microsoftonline.com/XXXXXXXXXXXXXXXXXXXXX/oauth2/v2.0/token";
const MS_GRAPH_SCOPE = "https://graph.microsoft.com/.default";
const GRANT_TYPE = "client_credentials";
const graphScopes = ["User.Read", "Mail.Send"]; // An array of graph scopes
const request = require("request");
const endpoint = TOKEN_ENDPOINT;
const requestParams = {
grant_type: GRANT_TYPE,
client_id: APP_ID,
client_secret: APP_SECERET,
scope: MS_GRAPH_SCOPE
};
request.post({
url: endpoint,
form: requestParams
}, function(err, response, body) {
if (err) {
console.log("error");
} else {
// console.log(response);
// console.log("Body=" + body);
let parsedBody = JSON.parse(body);
if (parsedBody.error_description) {
console.log("Error=" + parsedBody.error_description);
} else {
console.log("Access Token=" + parsedBody.access_token);
// testGraphAPI(parsedBody.access_token);
let accessToken = parsedBody.access_token;
getMe(accessToken);
}
}
});
function getMe(accessToken) {
require("isomorphic-fetch");
const fs = require("fs");
const MicrosoftGraph = require("#microsoft/microsoft-graph-client").Client;
const options = {
defaultVersion: "v1.0",
debugLogging: true,
authProvider: (done) => {
done(null, accessToken);
},
};
// https://github.com/microsoftgraph/msgraph-sdk-javascript/blob/dev/samples/node/main.js
// https://learn.microsoft.com/en-us/graph/overview
const client = MicrosoftGraph.init(options);
// send an email
const sendMail = {
message: {
subject: "Test o365 api from node",
body: {
contentType: "Text",
content: "Testing api."
},
toRecipients: [{
emailAddress: {
address: "test#abc.com"
}
}],
ccRecipients: [{
emailAddress: {
address: "test#abc.com"
}
}]
},
saveToSentItems: "false"
};
client.api('/users/test1#abc.onmicrosoft.com ').post(sendMail).then((res) => {
console.log(res);
}).catch((err) => {
console.log(err);
});
}
Can someone tell me where I am going wrong. Please help me out
I had the same error and it was a malformed url when sending to the users.
I think your url should be /users/test1#abc.onmicrosoft.com/sendMail

Categories