Node js send meeting/calendar invite for gmail - node.js

I am trying to send calendar invite using node js.
I have tried nodemailer library and is sending mail with calendar invite
Like in reference to this question
but this is sending invite like
but I want send invite like
suggest some help if anyone knows better approach.
[update]
using google-calendar api
the output is showing like

I would use the Google Calendar API: https://developers.google.com/google-apps/calendar/create-events, you can do this using a library such as https://www.npmjs.com/package/google-calendar. It also has the benefit that you won't have to send emails from your server.
In this way you can add attendees and the invite will be the same as if you sent the request directly from the calendar instead of Google interpreting your email as a calendar event.
The event you create appears on all the primary Google Calendars of
the attendees you included with the same event ID. If you set
sendNotifications to true on your insert request, the attendees will
also receive an email notification for your event. See the events with
multiple attendees guide for more information.

sendNotifications is deprecated, use sendUpdates. Notice it isn't boolean but string.
calendar.events.insert({
auth: auth,
calendarId: 'primary',
resource: event,
sendUpdates: 'all',
}, function(err, event) {
if (err) {
console.log('There was an error contacting the Calendar service: ' + err);
return;
}
console.log('Event created: %s', event.htmlLink);
});
From typescript signatures:
* #param {boolean=} params.sendNotifications Deprecated. Please use sendUpdates instead. Whether to send notifications about the creation of the new event. Note that some emails might still be sent even if you set the value to false. The default is false.
* #param {string=} params.sendUpdates Whether to send notifications about the creation of the new event. Note that some emails might still be sent. The default is false.

If someone is still looking for an answer :
Try updating your events.insert payload with sendNotifications key as shown
var calendar = google.calendar("v3");
calendar.events.insert({
auth: auth,
calendarId: "primary",
resource: event,
sendNotifications:true
}, function(err, event) {
if (err) {
console.log("There was an error contacting the Calendar service: " + err);
return;
}
console.log("Event created: %s", event);
});
This will send an email to all the attendees sent as part of event meta data as directed in google docs

Related

get username when user speaks to a dialogflow bot in Hangouts chat

I am building several bots with DialogFlow and Hangouts Chat integration.
How can I retrieve the user email of the user spraking to the bot ?
When I see the request sent from Hangouts chat to Dialogflow I cannot see any information about the user, it's like an anonymous request.
Has anybody find a workaround for that ?
It can be retrieved using events:
For each event like a message, a new user added or removed to the chat you can call event.user and it has the following fields:
event.user.name: The user name
event.user.email: The user email
event.user.displayName: The 'display' user name
event.user.avatarUrl: The user avatar's img url
For example, a working code using onMessage(event) function, for each interaction with the bot, the bot will answer with the user name and the message:
function onMessage(event) {
if (event.type == "MESSAGE" || event.space.type == "DM" ) {
var message = event.user.displayName + " said " + event.message.argumentText;
return { "text": message };
}
}
Response:
Benoit said How to get usernames on Hangouts bots?
A diagram of the JSON event format on Hangouts:
More documentation on hangouts events format and examples of use
Ok. Figured it out...
Indeed, you'll need to handle the intent using a Fullfilment.
In the default fullfilment function, you'll see this bit of code:
exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => {
const agent = new WebhookClient({ request, response });
console.log('Dialogflow Request headers: ' + JSON.stringify(request.headers));
console.log('Dialogflow Request body: ' + JSON.stringify(request.body));
//... REST OF THE CODE WHERE YOU 'LL HANDLE THE INTENTS
});
The event info that you normally get out of an apps script chat bot is in the
request.body
For example email:
const email = request.body.originalDetectIntentRequest.payload.data.event.user.email;
In that user object, you'll also find:
email
avatarUrl
displayName
Ok, solution here is to enable fulfilment and process this as a cloud function. The input json of the cloud function contains all the event json.
I wanted to reply back "Hello #name" without using cloud function

Twilio Function to send VoiceMail or Recording to Email

Twilio Stuido does not provide a native way to email a recording therefore this needs to be coded. In this example, a voicemail has been taken of a users call. Now that we have the recording a Twilio Function is created (NodeJS) to send this recording to email.
In the sample code below the function is failing however there is no available debug tool inside the Twilio Console for dealing with functions. NodeJS is fairly new to us so this maybe easy for someone to spot.
Possible other errors may be however:
Incorrect gmail authentication (although the details are correct in terms of username and password, perhaps this is not how you configure google apps to send the email)
Inability to import or incorrectly importation of the nodemailer dependency into Twilio
Bad NodeJS skills
The input variables are:
attachment
{{widgets.Voicemail_Recording.RecordingUrl}}
- which contains the URL to the voicemail recording.
lang
- the language of the caller (based on IVR choices earlier).
phone_number
{{trigger.call.From}}
NodeJS Twilio Function
var mailer = require('nodemailer');
mailer.SMTP = {
host: 'smtp.gmail.com',
port:587,
use_authentication: true,
user: 'info#example.com',
pass: '*********'
};
exports.handler = function(context, event, callback) {
mailer.send_mail({
sender: event.phone_number + '<info#example.com>',
to: 'info#example.com',
subject: 'Voicemail (' + event.lang + ')',
body: 'mail content...',
attachments: [{'filename': event.attachment, 'content': data}]
}), function(err, success) {
if (err) {
}
}
};
Sam here from Twilio's support team - I just released a blog post that should help with this. It shows how to forward voicemails with Studio, Functions, and SendGrid. Check it out here: https://www.twilio.com/blog/forward-voicemail-recordings-to-email

Cloud Functions for Firebase - action on email verified

Im trying to create a Cloud Function trigger that will execute after email has been verified.
In the Cloud Functions samples I could only find examples on triggers for onCreate and onDelete.
Within the documentation I found something about creating custom action handlers but I don't actually want to replace the standard email verification dialog they have by default, I just want to change the property of a "user" after the email is verified.
Does anyone have any experience with this, and is this even possible? Or is my only option to create my custom verification view/dialog webpage?
I faced this problem and took me a long time to figure it out how to solve so I hope this could help anyone that could get stuck into this too:
1 -> I created a function that was triggered with onCreate() for a new user
exports.sendConfirmationEmail = functions.auth.user()
.onCreate((user) => {
const actionCodeSettings = {
url: 'https://appNextURL.com/',
handleCodeInApp: false//ensure that the link will open into browser
};
return admin.auth().generateEmailVerificationLink(user.email, actionCodeSettings)
.then(async (link) => {
await db.collection('users').doc(user.uid).set({
verificationLink: link,
emailVerified: false
}, {merge: true});
return sendCustomVerificationEmail(user.email, user.displayName, link);
})
.catch((err) => {
console.error("Error:", err);
return Promise.reject(err);
});
});
The generateEmailVErificationLink() will generate the link based on the link we will save on step 3.
The function sendCustomVerificationEmail() is just an internal function that overcomes the standard email firebase send
2 -> Then I created a function that will receive a manual http trigger with the data that would be generated automatically by firebase when sending an automatic email
exports.verifyEmail = functions.https.onRequest((req, res) => {
const {mode, oobCode, apiKey, continueUrl, lang} = req.query;
const link = "https://us-central1-projectId.cloudfunctions.net/verifyEmail/?mode=" + encodeURIComponent(mode) + "&oobCode=" + encodeURIComponent(oobCode) + "&apiKey=" + encodeURIComponent(apiKey) + "&continueUrl=" + encodeURIComponent(continueUrl) + "&lang=" + encodeURIComponent(lang);
return db.collection("users")
.where("verificationLink", "==", link)
.get()
.then(function (querySnapshot) {
querySnapshot.forEach(function (user) {
const userData: UserData = user.data();
console.log("email verified: ", userData.userId);
return admin.auth().updateUser(userData.userId, {
emailVerified: true
}).then(function (userRecord) {
return db.collection('users').doc(userData.userId).set({emailVerified: true}, {merge: true});
});
});
return res.sendStatus(200).end();
}).catch(function (err) {
console.log("error:", err);
return res.sendStatus(403).end();
});
});
As I saved the link in the onCreate() I can now query that link to get who is the user that I am authenticating
3 -> the third step is to change the link in to Firebase Authentication template to the link generated into the 2nd step:
Navigate to Authentication>Templates:
Click on edit icon> Click on customize action URL:
Navigation
Paste the link generated into the step 2 and save:
Save link
Now every link generated automatically will go trought that function you created on step 2 and you will be able to handle the actions you want to happen.
I hope I could be clear.
you could still check for the verification status (at least) on Android with interface UserInfo method isEmailVerified(); eg. in order to send another verification email upon successful login, in case the current user has not yet verified the email address - and show the login screen again. one could as well HTTP trigger a cloud function or update values in the Firebase directly, through the client library. this might also apply to other platform clients, where one can check for the verification status.
this would not be exactly the event when the email just had been verified, but upon each single login attempt one knows the verification status and this value might be merely relevant on the client-side.
Create a publish button so your users trigger your cloud function
Instead of firing the cloud function immediately upon auth.emailVerified, I'm giving my users a 'Publish Profile' button which fires an http cloud function (passing in user.uid). This function looks up the user auth using the passed in user.uid
if user.uid && auth.emailVerified
write auth.emailVerified to each user.post
By default, post document "post.emailVerified" fields start out false, and cannot be written to except via adminFirestore in a cloud function.

Nodemailer with Gmail error: 454 4.7.0 Cannot authenticate due to temporary system problems

I am using nodemailer module with my nodejs/express.js app.
I am using gmail as the transporter.
It seems like every 20 successful emails sent, I will get this error:
454 4.7.0 Cannot authenticate due to temporary system problem
I'm testing out an invoice system so I'm regularly sending an email to the same email address for testing.
I am not using Google apps and I have set Gmail security to work with low security apps.
Invoices are important and if I cant guarantee all invoices will get sent to my customers, its going to be bad.
Is this normal?
app.get('/thankyou', function(req,res) {
var transporter = nodemailer.createTransport({
service: 'Gmail',
auth: {
user: 'somethinggggg#gmail.com',
pass: 'password here'
}
});
res.render('thankyou_email', function(err,html) {
var mailOptions = {
from: 'John Doe <somethinggggg#gmail.com>',
to: 'someoneee#icloud.com',
subject: 'Your order was received',
html: html
};
transporter.sendMail(mailOptions, function(error, info) {
if(error) {
console.log('error1: ' + error);
transporter.sendMail(mailOptions, function(error, info) {
if(error) {
console.log('error2: ' + error);
} else {
console.log('cool bro everything works2');
console.log(info);
}
});
} else {
console.log('cool bro everything works');
console.log(info);
}
});
res.render('thankyou_page');
});
As you can see, if I have an error I try to resend the email again, but still I receive the same error.
Also notice that I am using res.render() twice. I thought this was weird but it still works. The first res.render() I am using to generate the html for the email, and the last res.render() is to render the html in the response back to the client. I used to get an error about sending headers twice, but I don't see that error no more. Nevertheless ,it still worked.
Whose fault is this? Me? Nodemailer? Gmail?
If I were to sign up for Google apps will I still have this problem?
I have come across Nodemailer documentation and it was stated in Using OAuth2 that if a XOAuth2 token generator is used as the value for auth.xoauth2 when setting up transporter object then you do not need to set the value for user or pass as OAuth2 is used for authenticated.
XOAuth2 generator generates required accessToken itself if it is missing or expired. If authentication fails, a new token is requested and the authentication is retried once. If it still fails, an error is returned.
Sample code is given in the documentation. Though, I haven't personally tried using it, I hope it works with you. :)

Stripe module issues at Parse

I am developing a project which integrates Stripe + Parse for iOS. It uses web hooks and Cloud code via node js. Currently i am in need of implementing a couple of functions:
cancel user subscription with flag atPeriodEnd;
subscribe cancelled customer once again (named multiple subscriptions via Stripe docs).
As for the first one: I'm sending a request as follows in Parse's API -
Stripe.Customers.cancelSubscription(request.params.customerID, 1, null)
but the second parameter, i.e. atPeriodEnd remains 0 when i receive Stripe's response and my webhook catches request for cancelling user immediately. Also i have checked Stripe's dashboard to see parameters that i pass and it says 'No query parameters'. Hope you can help me with this one out.
Second one: as i mentioned earlier user needs to have ability to subscribe once again after cancellation. That means that i already have a valid customer saved at Stripe and all i need is to 'attach' to him a new subscription. There is a method for this at Stripe docs:
stripe.customers.createSubscription("cus_00000000000", { plan: "planName" }, function(err, subscription) {
});
But i can't find similar to this in Parse's API. Hope you can help with this one out.
Sorry if there are some mistakes or misunderstandings for you - feel free to ask, i will answer as much clear as i can. Thanks!
Here is a workaround to #1 - make an http call directly to the stripe endpoint using Parse.Cloud.httpRequest. (I agree that Stripe.Customers.cancelSubscription in the Parse cloud module does not seem to be working)
Parse.Cloud.define("cancel", function(request, response) {
var user = request.user;
var customerStripeId = user.get("stripeId");
var key = "<stripe_api_key>"
var url = "https://api.stripe.com/v1/customers/" + customerStripeId + "/subscription"
Parse.Cloud.httpRequest({
method: 'DELETE',
params: { at_period_end: true, key: key },
url: url,
success: function() {
response.success()
},
error: function(httpResponse) {
console.error('Delete failed with response code ' + httpResponse.status);
response.failure()
}
});
});

Resources