Send Grid API in Node.js - node.js

I am trying to get the contact list and check if the email recipient opened the email or not.
I found this code and tried but got 401.
import config from "#server/config"
sgClient.setApiKey(config.sendgridKey)
const headers = {
"on-behalf-of": "my account user name" // I put my account user name here
}
const request = {
url: `/v3/subusers`,
method: "GET"
} as any
const list = await sgClient
.request(request)
.then()
.catch((err) => {
console.log("list", err.response.body)
})
What do I need to put for the header 'on-behalf-of'? What does the subuser's user name?
And is there any example to get the 'email opened' event?
I am using Node.js.
Thank you!

Twilio SendGrid developer evangelist here.
The API you are trying to use there is the subuser API, not the contacts API. The subuser API is for managing subusers, which are accounts you can apply credit to and send emails from. Subusers are only available on Pro or Premier email accounts or Advanced Marketing Campaign accounts.
However, even if you were to use the Contacts API to get a list of your contacts, that's not the way to see if they have opened an email.
You should instead register for the Event Webhook. With the Event Webhook, SendGrid will send you webhook requests about events that occur as SendGrid processes your emails. These events include "processed", "delivered", "opened", and "clicked" and there are more in the documentation.
To handle the Event Webhook you need to create yourself an endpoint that can receive incoming HTTP requests. Here is an example from the documentation using Express.
const express = require('express');
const app = express();
app.use(express.json());
app.configure(function(){
app.set('port', process.env.PORT || 3000);
});
app.post('/event', function (req, res) {
const events = req.body;
events.forEach(function (event) {
// Here, you now have each event and can process them how you like
processEvent(event);
});
});
var server = app.listen(app.get('port'), function() {
console.log('Listening on port %d', server.address().port);
});

Related

How to send email using Angular and Node server?

I am able to send emails with nodejs using nodemailer but my project is in angular 6. I don't know how to integrate that nodejs code into my angular.I just want it for my website contact us forum. Thank you in advance.
You'd need to create a way of allowing your Angular code to talk to your Node.js code, typically you'd use a REST API using Http or Express.
For example, using Express:
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
const port = 8081;
app.use(bodyParser.json());
// Allow callers to send an email message
app.post('/send_email', function(req, res){
console.log('send_email body: ', req.body);
sendEmail(req.body);
res.status(201).json({status: 'success' });
});
app.listen(port);
function sendEmail(emailObj) {
// Send the mail
}
In Angular you can use the HttpClient module to call this, for example:
// Replace the url root as necessary
this.httpClient.post("http://127.0.0.1:8081/send_email",
{
"email": "user1#example.com",
"message": "Test message"
})
.subscribe(
data => {
console.log("POST Request is successful ", data);
},
error => {
console.log("Error", error);
}
);
It's worth noting that you will need to provide some authorization mechanism in the REST endpoint (e.g. POST send_email), since you don't want any old client sending mails.

Error: Can't set headers after they are sent. error received after refreshing a get request

The following code works as expected the first time it executes. The second time through it fails with the following error:
Error: Can't set headers after they are sent.
Basically, i'm trying to return a message from a series of published mqtt topics. I've tried several ways to do this but am at a loss as to this behavior. The code below shows an attempt using promises as detailed in this MDN article. I also tried using async / await (i can post this code as well if needed).
Concept
a get request arrives from a webpage, this triggers a mqtt message to be published to a local broker. a separate endpoint is listening for this topic. In this case a raspberry pi with a connected webcam. The topic is received the rpi does it's thing and publishes a return message with a url as it's data. the initial mqtt publisher is listening for this response and fires res.json() in response.
This works the first time, when i refresh the webpage it fails with Can't headers after they are sent. How does one reset res? It appears that this is the case.
punchitRoute.js
const express = require('express');
const punchitRoute = express.Router();
const mqtt = require('mqtt');
const client = mqtt.connect('mqtt://192.168.88.54:1883');
client.subscribe('returned', function(){
console.log('subscribed');
})
async function img(){
return new Promise(resolve =>{ client.on('message', function(topic, url){
const message = {
url: url.toString(),
name: "garfield",
date: Date.now()
}
return message;
})
})
}
punchitRoute.get('/', async function(req, res){
const mess = await img();
console.log(mess);
res.json(mess);
});
module.exports = punchitRoute;
server.js
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const punchit = require('./routes/punchitRoute');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended:false }));
app.get("/", (req, res) => {
res.json({
name: "Express application",
message: "welcome to punchit"
})
});
app.use('/api/punchit', punchit);
const PORT = process.env.PORT || 6040;
app.listen(PORT);
console.log('server started on: ', PORT);
My guess is that i am missing a basic fact of life regarding requests using express.
Thanks in advance for any guidance.
Thanks jfriend00 for pointing me in the right direction. First the code posted was completely incorrect. I was super confused with this and subsequently renamed the file punchitRoute file to keep working on it in a different approach, but forgot to rename the required file in server.js! That was a bonehead mistake.
The 2nd comment about event handler for client.on('message', ...) gave me the hint i needed to look into the event loop.
The idea here was to snap an image from a webcam using mqtt from a get request. The get request comes into the express server, triggers a subscription to a topic called 'returned' and publishes to a topic called 'sunrise' with the a message of 'click'.
There is a separate endpoint on a local network and listening to a local mqtt broker (both shared with the express server) that is listening for the 'sunrise' topic. This endpoint broadcast's 'returned' after the image has been saved into an S3 bucket and send the url of the image as the message back to the server running the get request. The mqtt functions work well, the issue I had was with the response event not terminating at the conclusion of the response. For this too work, several things had to change.
moved the res.send into a function called after client.on (this didn't completely work, it allowed the send to happen but still returned the error)
added event emitters to see which event were being triggered over and over again (this gave me some visibility into what was happening, but still didn't remove the error)
researched additional mqtt libraries (ended up staying with async-mqtt)
added client.unsubscribe for both topics after the res.send function (this had no effect)
finally found this answer which helped me to realize this whole time i could've just called client.once!
here's the code for the get request:
punchitRoute.get('/', async function(req, res){
//adding event listner 'send'
mqEvent.on('send', function(){
console.log('added send');
});
let sendit = function(url){
'send', //emmitting 'send'
res.status(200).send(
'<img src='+url.toString()+' />'+
'<h1>PUNCHED!</h1>'+
'<p>'+
'name: garfield <br/> time: '+moment(Date.now()).tz("America/Louisville").format('MM-DD-YYYY'));
}
client.subscribe('returned', function(){
console.log('subscribed');
});
client.publish('sunrise', 'click');
//changed this to .once and no more errors
await client.once('message', async function callout(topic, url){
try {
mqEvent.on('message', function(){
console.log('added message');
});
sendit(url.toString());
// console.log(res);
client.unsubscribe('returned', ()=>{
console.log('unsubscribed');
});
client.unsubscribe('sunrise', ()=>{
console.log('unsubscribed publish');
});
//clearing out the send event listeners
mqEvent.removeAllListeners('send');
console.log(mqEvent.listenerCount('send'));
//clearing out the message event listeners
mqEvent.removeAllListeners('message');
} catch(e){
console.log(e);
console.log('error');
}
})
});
Hopefully this can someone else faced with a similar issue.

how to reply message from web demo on dialogflow via webhook

I'm currently trying to add chatbot to my website.
I'm integrating web demo on the agent used for our lIne bot.
which some responses are handled by lambda webhook.
what I'm asking is can we send responses to web demo using lambda?
if can, then how do I send them?
there suppose to be some id right? and do we use HTTP post request to send them?
I couldn't find an example.
and for some intent which has more than one response handled by dialogflow it can only send one of them.
why is that? and what should I do so that I can send all of them via dialogflow?
Yes, it can be achieved and you can refer to give NodeJs code for that,
const express = require("express");
const bodyParser = require("body-parser");
const apiai = require("apiai");
const request = require("request");
const app = express();
app.use(bodyParser.json());
app.set("port", process.env.PORT || 5000);
app.post("/", (req, res) => {
//console.log(req.body)
const action = req.body.result.action;
if (!req.body || !req.body.result || !req.body.result.parameters) {
return res.status(400).send("Bad Request");
}
console.log("--------------------------------");
console.log("Action =>", action);
console.log("--------------------------------");
switch (action) {
case "price.search":
const webhookReply = `Sorry NO book found in store.`;
res.status(200).json({
source: "webhook",
speech: webhookReply,
displayText: webhookReply
});
break;
default:
break;
}
});
app.listen(app.get("port"), function() {
console.log("* Webhook service is listening on port:" + app.get("port"));
});
For every intent, there will be an action of that we have to define in dialogFlow.
So when the user enters any query your webhook will get triggered it will
go in the switch case to find the particular action and form that case you can send back the replay to your bot.

app to mail form data to my inbox doesn't work correctly on Firebase

I think I'm missing something very simple here. I have a simple, one page node.js app that uses nodemailer to email any form data to my inbox.
My index.js file:
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var nodemailer = require('nodemailer');
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
var transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: 'myemail#gmail.com',
pass: 'mypassword'
}
});
app.use(express.static('public')); //public folder with my html files
app.get('', function (req, res) {
res.sendFile(__dirname + "/");
})
app.post('/', function (req, res) {
response = {
name: req.body.name,
email: req.body.email,
message: req.body.message
};
var mailClient = {
from: 'myemail#gmail.com',
to: 'myemail#gmail.com',
subject: `Message from ${response.name}`,
text: 'MyMessage'
};
transporter.sendMail(mailClient, function (error, info) {
if (error) {
console.log(error); //not happening
} else {
res.redirect("/success.html"); //also not happening
}
});
})
var server = app.listen(80, function () {
var host = server.address().address
var port = server.address().port
console.log("App listening at http://%s:%s", host, port)
})
When I run this on my local machine using npm start in the root directory, the app runs perfectly fine on localhost. Nodemailer works properly; when I submit, my form data gets emailed to myself and I get redirected to my success page.
However, when I deploy this to Firebase, it seems the nodemailer part doesn't work. The page loads in with my static files, but when I try to submit anything via the form, the page simply refreshes (like when you have a submit button with bare html), instead of redirecting me to my success page and emailing data.
Is there something I need to change in my code to make it work with firebase?
Edit - no logs:
Google requires a paid account in order to make use of "Outbound Networking". The Free Tier does not allow you to make outbound calls. This would include sending mail to a remote mail server (like sending an email to a Yahoo, Gmail, or Outlook account).
See their pricing page for more info.
Look for "Outbound Networking".
If you'd like to leverage Gmail's API, you should still be able to use nodemailer with firebase functions and achieve what you're looking for and remain on the Free Tier. A fully working example is already available in the firebase-samples repository! I would like to highlight what the linked tutorial mentions, which is that Gmail does have an email sending quota that you should be aware of.
I tried to figure out problem in your code but didn't found any, I also have functionality to send email with verification code for authenticate/verify email id. For that I create one gmail id and gave that id/password for sending mail. Mails are sent from that gmail id with node.js when ever user register is email id we send email with veirfication code. My code is as under:
'use strict';
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const express = require('express');
var bodyParser = require('body-parser');
var users = require('./users/route');
const app = express();
const nodemailer = require('nodemailer');
// Configure the email transport using the default SMTP transport and a GMail account.
// For other types of transports such as Sendgrid see https://nodemailer.com/transports/
// TODO: Configure the `gmail.email` and `gmail.password` Google Cloud environment variables.
const gmailEmail = 'myapp#gmail.com';
const gmailPassword = 'password';
const gcm = require('node-gcm');
const mailTransport = nodemailer.createTransport(
`smtps://${gmailEmail}:${gmailPassword}#smtp.gmail.com`);
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({extended: false}))
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://myapp.firebaseio.com"
});
//admin.initializeApp(functions.config().firebase);
// Express middleware that validates Firebase ID Tokens passed in the Authorization HTTP header.
// The Firebase ID token needs to be passed as a Bearer token in the Authorization HTTP header like this:
// `Authorization: Bearer <Firebase ID Token>`.
// when decoded successfully, the ID Token content will be added as `req.user`.
const authenticate = (req, res, next) => {
if (!req.headers.authorization || !req.headers.authorization.startsWith('Bearer')) {
res.status(403).send('Unauthorized');
return;
}
const idToken = req.headers.authorization.split('Bearer ')[1];
admin.auth().verifyIdToken(idToken).then(decodedIdToken => {
req.user = decodedIdToken;
next();
}).catch(error => {
res.status(403).send('Unauthorized');
});
};
app.get("/token", (req, res) => {
res.status(200).send(admin.auth().applicationDefault());
admin.auth().createCustomToken(req.query.uid)
.then(function (customToken) {
res.status(200).send(customToken);
})
.catch(function (error) {
console.log("Error creating custom token:", error);
});
});
// GET /api/verifyEmail?code="1234"
app.get('/verifyEmail', (req, res) => {
// Get the one-time code from the query parameter.
var verificationCode = req.query.code;
var displayName = req.query.displayName;
var email = req.query.email; //If GET request
const mailOptions = {
from: `Linkuni <noreply#firebase.com>`,
to: email
};
// The user subscribed to the newsletter.
mailOptions.subject = `Welcome to Linkuni`;
mailOptions.text = `Hi ${displayName || ''}\n\n Welcome to Linkuni. We hope you will enjoy our service. Please enter this code:${verificationCode} into the app.\n\nThank you,\nLinkuni Team`;
return mailTransport.sendMail(mailOptions).then(() => {
console.log('Verification email sent to:', email);
});
});
Hope this helps!! :)

How to make Webhook for Slot Filling in Api.ai using backend Node js

how to do slot filling in api.ai using web-hooks for back-end Node.js, could you please any one let us know the process. Here is the sample response I have for creating sample webhook.
return res.json({
speech: "here is the sample one.",
displayText: "here is the sample one ",
data: {...},
contextOut: [{"name":"weather", "lifespan":2, "parameters":
{"city":"Rome"}}],
source: "from API"
});
Finally I got the answer first we need to enable the option called Domains, which is available in fulfillment tab in that we need to change option to Enable Webhook for all Domains. Below is the sample response with Node.js API, Using this response I am responding to the api.ai console. If any one having queries please post it #Here, Thank you.
const express = require('express');
const bodyParser = require('body-parser');
const restService = express();
restService.use(bodyParser.urlencoded({
extended: true
}));
restService.use(bodyParser.json());
restService.post('/echo', function(req, res) {
var speech = req.body.result && req.body.result.parameters && req.body.result.parameters.response1 ? req.body.result.parameters.response2 : "Seems like some problem."
return res.json({
speech: speech,
displayText: speech,
source: 'webhook-echo-sample'
});
});

Resources