ExpressJS + Express-mailer No default engine - node.js

I've developed my web app using ReactJS and I'm using as a server ExpressJS. Everithing was working fine until I implemented a /contactme endpoint which just must work as restful POST to send an email. I mean, my aim is just publishing an endpoint to send mails.
I'm using express-mailer for the job, but when I try to send an email using send method I'm getting this error:
message:"No default engine was specified and no extension was provided."
stack:"Error: No default engine was specified and no extension was provided.\n at new View (c:\React\web.facundolarocca.com\node_modules\express\lib\view.js:62:11)\n at EventEmitter.render (c:\React\web.facundolarocca.com\node_modules\express\lib\application.js:569:12)\n at sendMail (c:\React\web.facundolarocca.com\node_modules\express-mailer\lib\express-mailer.js:55:5)\n at Object.exports.extend.createSend [as send] (c:\React\web.facundolarocca.com\node_modules\express-mailer\lib\express-mailer.js:98:7)\n at c:\React\web.facundolarocca.com\server.js:28:16\n at Layer.handle [as handle_request] (c:\React\web.facundolarocca.com\node_modules\express\lib\router\layer.js:95:5)\n at next (c:\React\web.facundolarocca.com\node_modules\express\lib\router\route.js:131:13)\n at Route.dispatch (c:\React\web.facundolarocca.com\node_modules\express\lib\router\route.js:112:3)\n at Layer.handle [as handle_request] (c:\React\web.facundolarocca.com\node_modules\express\lib\router\layer.js:95:5)\n at c:\React\web....
I understand that ExpressJS needs some view engine to return html files, but in my case I'm going to respond a simpli JSON.
Below is my code:
var path = require('path');
var express = require('express');
var app = express();
var mailer = require('express-mailer');
var PORT = process.env.PORT || 3000;
app.use(express.static(path.join(__dirname, '/build')));
mailer.extend(app, {
from: 'no-reply#gmail.com',
host: 'smtp.gmail.com',
secureConnection: true,
port: 465,
transportMethod: 'SMTP',
auth: {
user: '*********#gmail.com',
pass: '**********'
}
});
app.get('/', function (req, res) {
//this is working fine
res.sendFile(__dirname + '/build/index.html')
});
app.get('/contactme', function (req, res) {
try {
app.mailer.send('test', {
to: 'myemaila#myemail.com.ar',
subject: 'some subject'
}, function (err) {
if (err) {
console.log(err);
res.status(400).json('There was an error sending the email');
} else {
res.status(200).json('Email Sent');
}
});
} catch (error) {
//Error is raised here
res.status(500).json(error);
}
});
app.listen(PORT, function (error) {
if (error) {
console.error(error);
} else {
console.info("==> 🌎 Listening on port %s. Visit http://localhost:%s/ in your browser.", PORT, PORT);
}
});
So I have two problems, on one hand is how to avoid this error , but in the other hand is why do I need an egine view .
I just expect, from the client side, to read the status code to show some message. I thought I could be able to implement in the same way as I was using restify.

My solution was to move to nodemailer. Here is the whole code:
package.json
{
"dependencies": {
"express": "^4.14.0",
"nodemailer": "^2.7.0",
"nodemailer-smtp-transport": "^2.7.2"
}
}
Code
server.post('/contactme', (req, res) => {
try{
let mailer = require('nodemailer')
let smtpTransport = require('nodemailer-smtp-transport')
let options = {
service: config.mailService.service,
secure: true,
auth: {
user: config.mailService.user,
pass: config.mailService.password
}
}
let transport = mailer.createTransport(smtpTransport(options))
let mail = {
from: 'from',
to: 'to',
subject: 'subject',
html: 'body'
}
transport.sendMail(mail, (error, response) => {
transport.close()
if (error) {
res.json(400, {error});
} else {
res.json(200, {response: 'Mail sent.'});
}
})
} catch(error) {
res.json(400, {error});
}
})

Related

Relay server of godaddy server issue with express app contact form

From my express application, I am trying to send the contact form from godaddy relay server. locally it works fine. but after I hosted with godaddy server it's not working. my local code: ( working using gmail properties )
app.post("/send_mail", function (req, res) {
let { text } = req.body;
const transporter = nodemailer.createTransport({
host: 'smtp.gmail.com',
port: 25,
secure: true,
auth: {
user: "xxxxxx#gmail.com",
pass: "xxxxxxxx"
}
});
let message = {
from: "from#email.com",
to: "xxxx#gmail.com",
subject: "Enquiry from Deane Project Management",
html: `
<hr />
<h1>Request for: ${text.option || "No title"}</h1>
<span>Name: ${text.username}</span><br/>
<span>Email: ${text.email}</span><br/>
<span>Phone: ${text.phone || "No phone"}</span><br/>
<span>Message:</span><br/>
<p>${text.message || "No message"}</p>
<hr />
`
}
transporter.sendMail(message, function (err, info) {
if (err) {
console.log(err);
} else {
console.log('sent', info);
}
});
res.send(200);
});
I am taken this reference,(https://in.godaddy.com/help/send-form-mail-using-an-smtp-relay-server-953#cpanel) relay server so updated my server app.js like this: But not works. I am not getting any error as well. from from end it's shows success message. But no email received yet.
app.post("/send_mail", function(req, res) {
let {text} = req.body;
const transporter = nodemailer.createTransport({
host: 'localhost',
port: 25,
secure: false
});
let message = {
from: "from#email.com",
to: "xxxxx#gmail.com",
subject: "Enquiry from Deane Project Management",
html: `
<hr />
<h1>Request for: ${text.option||"No title"}</h1>
<span>Name: ${text.username}</span><br/>
<span>Email: ${text.email}</span><br/>
<span>Phone: ${text.phone||"No phone"}</span><br/>
<span>Message:</span><br/>
<p>${text.message||"No message"}</p>
<hr />
`
}
transporter.sendMail(message, function(err, info) {
if (err) {
console.log(err);
} else {
console.log('sent',info);
}
});
res.send(200);
})

Ionic/Angular change Data in Node Server

I have create a Node application that uses the Twit(twitter api) to allow my ionic/Angular Application to post a tweet on twitter, however this problem that I have is that i get a 404 error message when I set the REST method to Post, it seems to work with a GET method.
However I do not know how I can dynamically change the Data in my node application from my Ionic Application.
I want to change the User's information and the Message that is being sent, but I do not know where to start. if anyone can guide me that will be appriecated.
this is my Node server.js file
const express = require('express');
const Twitter = require('twit');
const app = express();
const client = new Twitter({
consumer_key: '...',
consumer_secret: '...',
access_token: '...',
access_token_secret: '...',
});
app.use(require('cors')());
app.use(require('body-parser').json());
app.post('/post_tweet', (req, res) => {
tweet = {status:"Random"};
client
.post(`statuses/update`, tweet)
.then(timeline => {
console.log(timeline);
res.send(timeline);
})
.catch(error => {
res.send(error);
});
});
app.listen(3000, () => console.log('Server running'));
this is my twitter service in my Ionic application
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { map } from 'rxjs/operators';
#Injectable({
providedIn: 'root'
})
export class TwitterserviceService {
api_url = 'http://localhost:3000';
constructor(private http: HttpClient) { }
tweet(tweetdata: string) {
return this.http.get<any>(`${this.api_url}/post_tweet`)
.pipe(map(tweet => {
alert("tweet posted")
return tweet;
}));
}
}
and this is the method that I use to send a Post, however the message "this works" doesent post instead the default message in the Node application is sent "random"
sendTweet() {
this.api.tweet('this works')
.pipe(first())
.subscribe(
data => {
console.log('yes')
},
error => {
'failed'
});
}
Your service should do a POST, not a GET. And a POST must have a body.
tweet(tweetdata: string) {
return this.http.post<any>(`${this.api_url}/post_tweet`, { tweetdata })
}
note that you will have to handle this body in the express route and probably do something with this tweetdata attribute.
Alright I have found the answer and it was actually quite simple
here it the link to the resource that i am using => https://code.tutsplus.com/tutorials/connect-to-the-twitter-api-in-an-angular-6-app--cms-32315
this is my node js code
const express = require('express');
const Twitter = require('twit');
const app = express();
const client = new Twitter({
consumer_key: '...',
consumer_secret: '...',
access_token: '...',
access_token_secret: '...',
});
app.use(require('cors')());
app.use(require('body-parser').json());
app.post('/post_tweet', (req, res) => {
tweet = req.body;
client
.post(`statuses/update`, tweet)
.then(tweeting => {
console.log(tweeting);
res.send(tweeting);
})
.catch(error => {
res.send(error);
});
});
app.listen(3000, () => console.log('Server running'));
and here it the code that I have in my Ionic/Angular Project
api_url = 'http://localhost:3000';
tweet(tweetdata: string) {
return this.http.post<any>(`${this.api_url}/post_tweet/`, {status: tweetdata})
.pipe(map(tweet => {
alert("tweet posted")
return tweet;
}));
}
sendTweet() {
this.tweet('This is app code')
.pipe(first())
.subscribe(
data => {
console.log('yes')
},
error => {
'failed'
});
}
hope this helps someone.

Sending email using nodemailer not working

I have this sendMail cloud function here through i am trying to send a simple email. I am not sure what is the mistake i am doing but i keep getting 400 Bad request error on postman whenever i hit this function.
P.S i am adding correct credentials of my gmail account too
Here is my cloud function
const functions = require('firebase-functions');
const cors = require('cors')({origin: true});
const admin = require("firebase-admin");
const bodyParser = require("body-parser");
const nodemailer = require("nodemailer");
var smtpTransport = require('nodemailer-smtp-transport');
let transporter = nodemailer.createTransport(smtpTransport({
service: 'Gmail',
auth: {
user: 'abc#gmail.com',
pass: '12345'
}
}));
//Send email
exports.sendMail = functions.https.onRequest((request, responde) => {
// cors(req, res, () => {
// getting dest email by query string
res.set('Access-Control-Allow-Origin', '*');
res.set('Access-Control-Allow-Methods', 'GET', 'POST');
res.set('Access-Control-Allow-Headers', 'Content-Type');
if(req.method === 'OPTIONS') {
res.end();
}
else
{
if(req.body.dest != null || req.body.dest != undefined) {
const dest = req.query.dest;
const mailOptions = {
from: 'Ehsan Nisar <ABC#gmail.com>',
to: dest,
subject: 'I\'M A PICKLE!!!', // email subject
html: `<p style="font-size: 16px;">Pickle Riiiiiiiiiiiiiiiick!!</p>
<br />
<img src="https://images.prod.meredith.com/product/fc8754735c8a9b4aebb786278e7265a5/1538025388228/l/rick-and-morty-pickle-rick-sticker" />
` // email content in HTML
};
// returning result
return transporter.sendMail(mailOptions, (erro, info) => {
if(erro){
return res.send(erro);
}
return res.send('Sended');
});
}
else {
res.send(400, {
"message": "All fields are required"
})
}
// });
}
});

How to put authentication on hapi-swagger documentation page so that only authentic user could see my documentation

I am making API with hapi-swagger and I have implemented basic-authentication. But even if user doesn't have authentication he can still view my documentation page. I want to prevent him from viewing my documentation page. How can I implement basic auth on swagger documentation page?
I want to hide this page and ask for authentication credentials before rendering documentation
const Hapi = require('#hapi/hapi');
const basicAuth = require('basic-auth');
const server = new Hapi.server({ port: process.env.port || 3005, host: "localhost" });
server.ext('onRequest', (req, h) => {
const route = req.url.pathname;
if (route === "/documentation") {
let user = basicAuth(req);
if (user === undefined || user['name'] !== 'username' || user['pass'] !== 'pwd') {
return h.response("Unauthorized")
.code(401)
.header('WWW-Authenticate', 'Basic realm="Node"')
.takeover()
}
}
return h.continue;
});
const startServer = async () => {
await server.register([
require('#hapi/vision'),
require('#hapi/inert'),
{
plugin: require('hapi-swagger'),
options: {
info: {
title: 'Doc',
},
schemes: ["http", "https"],
securityDefinitions: {},
security: [],
}
}]);
await server.start();
console.log(`Server running at: ${server.info.uri}`);
};
process.on('unhandledRejection', (err) => {
console.error(err);
console.error(err.stack);
process.exit(1);
});
startServer();
You need to set property auth on plugin registration.
Eg.
await server.register([
{
plugin: require('hapi-swagger'),
options: {
auth: 'my-oauth-strategy',
}
}]);

Error with messenger webhook setup

I am using the same verify token but it's giving me error https://infinite-dusk-17985.herokuapp.com/webhook/ and neither it's responding when I m using it on messenger.
'use strict';
const express = require('express')
const bodyParser = require('body-parser')
const request = require('request')
const app = express()
app.set('port', (process.env.PORT || 5000))
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({extended: false}))
// parse application/json
app.use(bodyParser.json())
// index
app.get('/', function (req, res) {
res.send('hello world i am a secret bot')
})
// for facebook verification
app.get('/webhook/', function (req, res) {
if (req.query['hub.verify_token'] === 'my_voice_is_my_password_verify_me') {
res.send(req.query['hub.challenge'])
res.send('Sucess, Challenge loop crossed')
}
res.send('Error, wrong token')
})
// to post data
app.post('/webhook/', function (req, res) {
let messaging_events = req.body.entry[0].messaging
for (let i = 0; i < messaging_events.length; i++) {
let event = req.body.entry[0].messaging[i]
let sender = event.sender.id
if (event.message && event.message.text) {
let text = event.message.text
if (text === 'Generic') {
sendGenericMessage(sender)
continue
}
sendTextMessage(sender, "Text received, echo: " + text.substring(0, 200))
}
if (event.postback) {
let text = JSON.stringify(event.postback)
sendTextMessage(sender, "Postback received: "+text.substring(0, 200), token)
continue
}
}
res.sendStatus(200)
})
const token = "EAACKS5K1KvkBAASh07gKvgk9LvjCweLqKxKti1ZBzdzArNFPYNX9ZCx9tu35NNWquJZBuZCdZBLdsZBJAPFhvKgMZBDlazgofkbZAAeE6Hgv3gOh8jRd1W42AAZBIBd7EYNJsADepcpIgSlJEH9kHrup49oT5wZBHZBItnQwwDqr96z4wZDZD"
function sendTextMessage(sender, text) {
let messageData = { text:text }
request({
url: 'https://graph.facebook.com/v2.6/me/messages',
qs: {access_token:token},
method: 'POST',
json: {
recipient: {id:sender},
message: messageData,
}
}, function(error, response, body) {
if (error) {
console.log('Error sending messages: ', error)
} else if (response.body.error) {
console.log('Error: ', response.body.error)
}
})
}
function sendGenericMessage(sender) {
let messageData = {
"attachment": {
"type": "template",
"payload": {
"template_type": "generic",
"elements": [{
"title": "First card",
"subtitle": "Element #1 of an hscroll",
"image_url": "http://messengerdemo.parseapp.com/img/rift.png",
"buttons": [{
"type": "web_url",
"url": "https://www.messenger.com",
"title": "web url"
}, {
"type": "postback",
"title": "Postback",
"payload": "Payload for first element in a generic bubble",
}],
}, {
"title": "Second card",
"subtitle": "Element #2 of an hscroll",
"image_url": "http://messengerdemo.parseapp.com/img/gearvr.png",
"buttons": [{
"type": "postback",
"title": "Postback",
"payload": "Payload for second element in a generic bubble",
}],
}]
}
}
}
request({
url: 'https://graph.facebook.com/v2.6/me/messages',
qs: {access_token:token},
method: 'POST',
json: {
recipient: {id:sender},
message: messageData,
}
}, function(error, response, body) {
if (error) {
console.log('Error sending messages: ', error)
} else if (response.body.error) {
console.log('Error: ', response.body.error)
}
})
}
// spin spin sugar
app.listen(app.get('port'), function() {
console.log('running on port', app.get('port'))
})
Any help would be highly appreciated.
Since you didn't share the error stack trace, I am not sure about the reason. But, there is an issue with your code.
For the following code snippet,
// for facebook verification
app.get('/webhook/', function (req, res) {
if (req.query['hub.verify_token'] === 'my_voice_is_my_password_verify_me') {
res.send(req.query['hub.challenge'])
res.send('Sucess, Challenge loop crossed')
}
res.send('Error, wrong token')
})
You would definitely be getting Error: Can't set headers after they are sent.
So, update the code with the following.
// for facebook verification
app.get('/webhook/', function (req, res) {
if (req.query['hub.verify_token'] === 'my_voice_is_my_password_verify_me') {
res.send(req.query['hub.challenge'])
console.log('Sucess, Challenge loop crossed')
} else{
res.send('Error, wrong token')
}
})
Here is a working solution:
// my_server.js
'use strict';
const express = require('express');
const bodyParser = require('body-parser');
const request = require('request');
const app = express();
app.set('port', process.env.PORT || 5000);
// parse application/json
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
// spin spin sugar
app.listen(app.get('port'), function() {
console.log('running on port', app.get('port'));
});
/* for facebook verification */
app.get('/webhook', function(req, res) {
if (req.query['hub.verify_token'] === 'my_voice_is_my_password_verify_me') {
console.log("Validating webhook");
res.status(200).send(req.query['hub.challenge']);
} else {
console.error("Verification failed. Make sure the validation tokens match.");
res.status(403).end();
}
});
Few things to take note:
When you setup the webhook at developers.facebook.com, make sure the Verification Token you provide their is exactly the same string as found in the above code (i.e. 'my_voice_is_my_password_verify_me')
If you wish to change this token, make sure you update it at both places. This is Very Important
If you deploy this code to Heroku, process.env.PORT will be your port. A hardcoded port number might not work!
You will notice app.use(bodyParser.json()); is used here. This is because Facebook sends JSON data (payload) in the request body
Note that you can't write 2 res.send() statements it will give you error as mentioned by Mukesh. Once the headers are sent it can't be modified
Finally as a best practice, you can try to run it locally using npm run start or node my_server.js and ensure it has no errors like a missing node module & etc although you won't get a success response while running it locally

Resources