I am trying to send an email to myself after a purchase has been made via stripe. I currently have a personal and business email that I am using for this. I am new to node.js, and I'm confused as to why this is not working.
What makes sense to me is to add this code as an argument to the .then callback. When testing this out locally, the success page renders, however no emails are sent and the two console.log's at the bottom are not being outputted to the console. The following is my app.js
const express = require('express');
const stripe = require('stripe')('mystripekey');
const bodyParser = require('body-parser');
const exphps = require('express-handlebars');
const nodemailer = require('nodemailer')
var app = express();
var transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: 'myemail#gmail.com',
pass: 'mypassword'
}
});
app.engine('handlebars', exphps({defaultLayout: 'main'}));
app.set('view engine', 'handlebars')
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));
app.use(express.static(`${__dirname}/public`));
app.get('/', (req, res) => {
res.render('index');
});
app.post('/charge', (req, res) => {
const amount = 25000;
stripe.customers.create({
email: req.body.stripeEmail,
source: req.body.stripeToken
})
.then(customer => stripe.charges.create({
amount,
description: 'Advertisement',
currency: 'usd',
customer: customer.id
}))
.then(charge => {
// This is where I'm getting confused
res.render('success')
var mailOptions = {
from: req.body.stripeEmail,
to: 'mybizemail#gmail.com',
subject: 'A purchase was made',
text: req.body.stripeEmail + ' made a purchase!'
};
transporter.sendMail(mailOptions, function(error, info){
if (error) {
console.log(error);
} else {
console.log('Email sent: ' + info.response);
}
});
});
});
I expected either an error message to be logged or the email sent to be logged but that is not happening. Any help is greatly appreciated.
I think the node mailer code is never getting called. Try putting the res.render in callback in transporter.sendMail.
Like so:
.then(charge => {
console.log("charge>", charge);
var mailOptions = {
from: req.body.stripeEmail,
to: 'mybizemail#gmail.com',
subject: 'A purchase was made',
text: req.body.stripeEmail + ' made a purchase!'
};
console.log("mailOptions>", mailOptions);
transporter.sendMail(mailOptions, function(error, info){
console.log("error1>", error);
console.log("info>", info);
if (error) {
console.log(error);
res.render('error')
} else {
console.log('Email sent: ' + info.response);
res.render('success')
}
});
});
Related
I've created a server using NodeJs on localhost:3000 for my angular application. When user will submit contact form, server will run the script and send an email.
Everything working fine on localhost but when I upload on Cpanel, its giving an error Internal Server Error: 500.
I've created Node application from Cpanel. Root file is server.js. var http is auto generated by Cpanel. Rest of the things, I've added.
Server.js
const express = require('express');
const sendMail = require('./mail.js');
const bodyParser = require('body-parser');
const cors = require('cors');
var http = require('http');
const app = express();
app.use(bodyParser.json());
app.use(cors());
var server = http.createServer(function(req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
var message = 'It works!\n',
version = 'NodeJS ' + process.versions.node + '\n',
response = [message, version].join('\n');
res.end(response);
});
server.listen();
app.post('/submit', function(req, res) {
const { name, email, phone, subject, message} = req.body;
console.log(req.body);
res.status(200).json({message: req.body});
sendMail(name, email, phone, subject, message, function(err, data) {
if(err) {
res.status(500).json({ message: 'Internal Error'});
} else {
res.json({message: 'Email Sent!!!!!'});
}
});
})
mail.js
const nodemailer = require('nodemailer');
const mailGun = require('nodemailer-mailgun-transport');
const auth = {
auth: {
api_key: 'privatekey-381f2624-ccbf9964',
domain: 'domain-17bb134be0f54584b0e8751d3a3ec19b.mailgun.org'
}
};
const transporter = nodemailer.createTransport(mailGun(auth));
const sendMail = (name, email, phone, subject, message, cb) => {
const mailOptions = {
from: email,
to: 'webmaster#gmail.com',
subject: subject,
text: 'Name: ' + name + '\n Email:' + email + '\n Phone: ' + phone + '\n Message: ' + message
};
transporter.sendMail(mailOptions, function(err, data) {
if(err) {
cb(err, null);
} else {
cb(null, data);
}
});
}
module.exports = sendMail;
Angular EmailService where I placed this api link.
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
#Injectable({
providedIn: 'root'
})
export class EmailService {
_url = 'https://gump.akc-uae.com/api/submit';
constructor(private _http: HttpClient) { }
contact(clientData:any) {
return this._http.post<any>(this._url, clientData);
}
}
Its my first attempt to upload Node app on Cpanel.
ok. you were calling the sendMail function after sending the response.
Your code should be:
app.post('/submit', async function(req, res) {
const { name, email, phone, subject, message} = req.body;
try{
await sendMail(name, email, phone, subject, message,
function(err, data) {
if(err) {
res.status(500).json({ message: 'Internal Error'});
} else {
res.json({message: 'Email Sent!!!!!'});
}
});
res.status(200).json({message: req.body});
}catch(error){
res.json({message: error.message});
}
})
Note: make your sendMail function promise
I'm pretty new to the space so not sure how obvious this question is. I've created a contact page for a simple website that is hosting live with a domain name. On localhost the contact page operates perfectly and the message is received successfully. However, when I attempt to submit the contact form during the web hosting i get the alert "something went wrong!" from the app.js file. I've created a html contact form, app.js and server.js file. I've also used the nodemailer extension.
Here is the app.js file:
let pname = document.getElementById('name');
let email = document.getElementById('email');
let phone = document.getElementById('phone');
let subject = document.getElementById('subject');
let message = document.getElementById('message');
contactForm.addEventListener('submit', (e)=>{
e.preventDefault();
let formData = {
pname: pname.value,
email: email.value,
phone: phone.value,
subject: subject.value,
message: message.value
}
let xhr = new XMLHttpRequest();
xhr.open('POST', '/');
xhr.setRequestHeader('content-type', 'application/json');
xhr.onload = function(){
console.log(xhr.responseText);
if(xhr.responseText == 'success'){
alert('Your email has been sent! ###### will be in touch shortly.');
pname.value = '';
email.value = '';
phone.value = '';
subject.value = '';
message.value = '';
}else{
alert('Something went wrong!')
}
}
xhr.send(JSON.stringify(formData));
})
Here is the server.js file:
const express = require('express');
const app = express();
const nodemailer = require("nodemailer");
const PORT = process.env.PORT || 5001;
//middleware
app.use('/',express.static(__dirname));
app.use(express.static('public'))
app.use(express.json())
function ignoreFavicon(req, res, next) {
if (req.originalUrl.includes('favicon.ico')) {
res.status(204).end()
}
next();
}
app.use(ignoreFavicon);
app.get('/', (req, res)=>{
res.sendFile(__dirname + '/public/contact.html');
})
app.post('/', (req, res)=>{
console.log(req.body);
const transporter = nodemailer.createTransport({
pool: true,
host: "smtp.gmail.com",
port: 465,
secure: true,
auth: {
user: "######",
pass: "######"
}
})
const mailOptions = {
from: '######',
to: '######',
subject:`You have a message from ${req.body.pname} (${req.body.email}) Subject: (${req.body.subject}) Ph: (${req.body.phone})`,
text: req.body.message
}
transporter.sendMail(mailOptions, (error, info)=>{
if(error){
console.log(error);
res.send('error');
}else{
console.log('Email sent: ' + info.response);
res.send('success')
}
})
})
app.listen(PORT, ()=>{
console.log(`Server running on port ${PORT}`)
})
Thank you!
I'm trying to use Nodemailer in a React/Express app I'm working on and on the server it says it's posting but in the network tab its showing pending and then it never goes through? Here's my code:
const express = require('express');
const router = express.Router();
const nodemailer = require('nodemailer');
require("dotenv").config();
// router.get('/', () => {
// resizeBy.send('Welcome to my email form')
// });
module.exports = () => {
router.post('/', (req, res) => {
console.log("inside event handler")
let transporter = nodemailer.createTransport({
service: 'Gmail',
port: 465,
auth: {
user: process.env.EMAIL,
pass: process.env.PASSWORD
}
});
let mailOptions = {
from: process.env.EMAIL,
to: `${req.body.values.email}`,
subject: `Message from: ${process.env.EMAIL}`,
html: `
<h3>Information</h3>
<ul>
<li>Name: ${req.body.values.name}</li>
<li>Email: ${req.body.values.email}</li>
</ul>
<h3>Message</h3>
<p>${req.body.values.message}</p>
`
}
transporter.sendMail(mailOptions, (err, response) => {
if (err) {
res.send(err)
console.log("Error happened in send email", err)
} else {
res.send('Success! Message sent!')
console.log("Message sent")
}
})
transporter.close();
})
return router;
}
It looks like you don't need to use transporter.close() since you aren't pooling connections. Using it in this context is probably your problem.
transporter.sendMail() is async so you are sending mail and then immediately closing it with transporter.close(). This means the sendMail callback isn't fired, which in turn means res.send() is never sent, which results in your never ending and pending http request to your client.
I suggest removing the transporter.close() line and retrying.
I'm using Nodemailer for sending a forget password mail with Gmail service.I tried to reach to the same error earlier in the StackOverflow, but I couldn't find the solution. Please help me, I have no idea why it is giving error like,
"TypeError: Cannot create property 'mailer' on string 'smtpTransport'"
Here is my code below-
var nodemailer = require('nodemailer');
app.post('/forgot', function(req, res, next) {
async.waterfall([
function(done) {
crypto.randomBytes(20, function(err, buf) {
var token = buf.toString('hex');
done(err, token);
});
},
function(token, done) {
User.findOne({ email: req.body.email }, function(err, user) {
if (!user) {
req.flash('error', 'No account with that email address exists.');
return res.redirect('/forgot');
}
user.resetPasswordToken = token;
user.resetPasswordExpires = Date.now() + 3600000; // 1 hour
user.save(function(err) {
done(err, token, user);
});
});
},
function(token, user, done) {
console.log(token, "Token");
console.log(user, "user")
var smtpTransport = nodemailer.createTransport('SMTP', {
service: 'gmail',
auth: {
user: 'abc#gmail.com',
pass: '123456'
}
});
var mailOptions = {
to: user.email,
from: 'myproducts#mailinator.com',
subject: 'My Products Password Reset',
text: 'You are receiving this because you (or someone else) have requested the reset of the password for your account.\n\n' +
'Please click on the following link, or paste this into your browser to complete the process:\n\n' +
'http://' + req.headers.host + '/reset/' + token + '\n\n' +
'If you did not request this, please ignore this email and your password will remain unchanged.\n'
};
smtpTransport.sendMail(mailOptions, function(err) {
req.flash('info', 'An e-mail has been sent to ' + user.email + ' with further instructions.');
done(err, 'done');
});
}
], function(err) {
if (err) return next(err);
res.redirect('/forgot');
});
});
And the error is something like this-
/home/cis/Desktop/myproducts/node_modules/mongodb/lib/utils.js:132
throw err;
^
TypeError: Cannot create property 'mailer' on string 'smtpTransport'
at Mail (/home/cis/Desktop/myproducts/node_modules/nodemailer/lib/mailer/index.js:45:33)
at Object.module.exports.createTransport (/home/cis/Desktop/myproducts/node_modules/nodemailer/lib/nodemailer.js:52:14)
at /home/cis/Desktop/myproducts/app.js:185:38
at nextTask (/home/cis/Desktop/myproducts/node_modules/async/dist/async.js:5310:14)
at next (/home/cis/Desktop/myproducts/node_modules/async/dist/async.js:5317:9)
at /home/cis/Desktop/myproducts/node_modules/async/dist/async.js:958:16
at /home/cis/Desktop/myproducts/app.js:177:11
at /home/cis/Desktop/myproducts/node_modules/mongoose/lib/model.js:3913:16
at model.$__save.error (/home/cis/Desktop/myproducts/node_modules/mongoose/lib/model.js:342:7)
at /home/cis/Desktop/myproducts/node_modules/kareem/index.js:297:21
at next (/home/cis/Desktop/myproducts/node_modules/kareem/index.js:209:27)
at Kareem.execPost (/home/cis/Desktop/myproducts/node_modules/kareem/index.js:217:3)
at _cb (/home/cis/Desktop/myproducts/node_modules/kareem/index.js:289:15)
at $__handleSave (/home/cis/Desktop/myproducts/node_modules/mongoose/lib/model.js:280:5)
at /home/cis/Desktop/myproducts/node_modules/mongoose/lib/model.js:208:9
at args.push (/home/cis/Desktop/myproducts/node_modules/mongodb/lib/utils.js:404:72)
[nodemon] app crashed - waiting for file changes before starting...
The Nodemailer structure has been changed, try use this :
smtpTransport = nodemailer.createTransport({
service: 'Gmail',
auth: {
xoauth2: xoauth2.createXOAuth2Generator({
user: 'youremail#gmail.com',
//and other stuff here
});
}
});
var nodemailer = require("nodemailer");
var smtpTransport = nodemailer.createTransport({
service: "Yahoo", // sets automatically host, port and connection security settings
auth: {
user: "xxxxxxxxxx95#yahoo.com",
pass: "xxxxxxxxxxxx"
}
});
function mail(messageBody) {
let messageBodyJson = JSON.stringify(messageBody)
smtpTransport.sendMail({ //email options
from: "xxxxxxxxxx95#yahoo.com", // sender address. Must be the same as authenticated user if using Gmail.
to: "xxxxxxxxxx95#gmail.com", // receiver
subject: "Emailing with nodemailer", // subject
text: messageBodyJson // body
}, function(error, response){ //callback
if(error){
console.log("error",error);
}else{
console.log(response);
}
// smtpTransport.close(); // shut down the connection pool, no more messages. Comment this line out to continue sending emails.
});
}
mail("your mail message");
Try this.
Link to a similar question
Gmail / Google app email service requires OAuth2 for authentication. PLAIN text password will require disabling security features manually on the google account.
To use OAuth2 in Nodemailer, refer: https://nodemailer.com/smtp/oauth2/
Sample code:
var email_smtp = nodemailer.createTransport({
host: "smtp.gmail.com",
auth: {
type: "OAuth2",
user: "youremail#gmail.com",
clientId: "CLIENT_ID_HERE",
clientSecret: "CLIENT_SECRET_HERE",
refreshToken: "REFRESH_TOKEN_HERE"
}
});
I am very stuck with a routing error on express.js. I am using jade to render my page views. I have read all the docs and refactored many times to no avail.
This is the plain contents of the link that is pointing to the '/sell' route.
index.jade
include layout
html
button.btn.btn-primary(type='submit', href='/sell') Add Item
When clicking this button the browser returns the following as a 404:
Cannot GET /sell
The problem here is that all other routes work correctly, if you are to modify the above href to other pages i.e. '/' , '/sign_in', etc no error occurs. The problem appears to be isolated to the '/sell' route.
The controller with the '/sell' route is below:
server.js
var dotenv = require('dotenv');
dotenv.load();
var session = require('express-session')
var nodemailer = require('nodemailer');
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var bcrypt = require('bcrypt');
var async = require('async');
var crypto = require('crypto');
var cookieParser = require('cookie-parser');
var flash = require('express-flash');
var express = require('express');
var app = express();
var mongoose = require('mongoose');
var root = __dirname;
var path = require('path');
var User = require('./models/user');
var bodyParser = require('body-parser');
var errorHelper = require('mongoose-error-helper').errorHelper;
var validator = require('validator');
var Item = require("./models/item")
var username, email, password, owner, product_name, condition, details, price;
mongoose.connect(process.env.MONGODB_CONGO_DEV);
// Middleware
app.set('views', 'app/views');
app.set('view engine', 'jade');
app.set('port', process.env.PORT || 3000);
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true}));
app.use(cookieParser());
app.use(session( {
secret: 'session secret key',
resave: false,
saveUninitialized: true
}));
app.use(flash());
app.use(passport.initialize());
app.use(passport.session());
// Routing
app.get('/', function(req,res) {
res.render('index', {
title: 'Congo',
message: 'Congo',
user: req.user
});
});
app.get('/sell', function(req,res) {
res.render('item', {
title: 'Congo - Sell',
message: 'Sell',
user: req.user
});
});
app.get('/sign_in', function(req,res) {
res.render('sign_in', {
title: 'Congo',
message: 'sign in motherfucker',
user: req.user
});
});
app.post('/sign_in', function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
if (err) return next(err)
if (!user) {
req.flash('error', 'Incorrect login details');
return res.redirect('/sign_in')
};
req.logIn(user, function(err) {
if (err) return next(err);
res.
return res.redirect('/');
});
})(req, res, next);
});
app.get('/sign_up', function(req, res) {
res.render('sign_up', {
title: 'Congo',
message: 'sign up',
user: req.user
});
});
app.post('/sign_up', function(req, res) {
var user = new User({
username: req.body.username,
email: req.body.email,
password: req.body.password
});
if (req.body.confirm != req.body.password) {
req.flash('error', 'Password do not match')
res.redirect('/sign_up')
};
else if (validator.isEmail(req.body.email) === false) {
req.flash('error', 'Invalid email address')
res.redirect('/sign_up')
};
else {
user.save(function(err) {
if (err) {
req.flash('error', 'Email already in use')
res.redirect('/sign_up')
} else {
req.logIn(user, function(err) {
res.redirect('/');
});
}
});
};
});
app.get('/logout', function(req, res){
req.logout();
res.redirect('/');
});
app.get('/forgot', function(req, res) {
res.render('forgot', {
user: req.user,
message: 'you wally'
});
});
app.get('/profile', function(req, res) {
res.render('profile', {
user: req.user,
message: 'User profile'
});
});
app.post('/forgot', function(req, res, next) {
async.waterfall([
function(done) {
crypto.randomBytes(20, function(err, buf) {
var token = buf.toString('hex');
done(err, token);
});
},
function(token, done) {
User.findOne({ email: req.body.email }, function(err, user) {
if (!user) {
req.flash('error', 'No account with that email address exists.');
return res.redirect('/forgot');
};
user.resetPasswordToken = token;
user.resetPasswordExpires = Date.now() + 3600000; // 1 hour
user.save(function(err) {
done(err, token, user);
});
});
},
function(token, user, done) {
var smtpTransport = nodemailer.createTransport('SMTP', {
service: 'Gmail',
auth: {
user: 'harryandrew.dix#gmail.com',
pass: process.env.GMAIL_PASS
};
});
var mailOptions = {
to: user.email,
from: 'passwordreset#demo.com',
subject: 'Node.js Password Reset',
text: 'You are receiving this because you (or someone else) have requested the reset of the password for your account.\n\n' +
'Please click on the following link, or paste this into your browser to complete the process:\n\n' +
'http://' + req.headers.host + '/reset/' + token + '\n\n' +
'If you did not request this, please ignore this email and your password will remain unchanged.\n'
};
smtpTransport.sendMail(mailOptions, function(err) {
req.flash('info', 'An e-mail has been sent to ' + user.email + ' with further instructions.');
done(err, 'done');
});
};
], function(err) {
if (err) return next(err);
res.redirect('/forgot');
});
});
app.get('/reset/:token', function(req,res) {
User.findOne({resetPasswordToken: req.params.token, resetPasswordExpires: { $gt: Date.now()}}, function(err,user) {
if (!user) {
req.flash('error', 'Password reset token invalid or expired.');
return res.redirect('/forgot');
}
res.render('reset', {
user: req.user,
message: 'reset dem pass'
});
});
});
app.post('/reset/:token', function(req, res) {
async.waterfall([
function(done) {
User.findOne({ resetPasswordToken: req.params.token, resetPasswordExpires: { $gt: Date.now() } }, function(err, user) {
if (!user) {
req.flash('error', 'Password reset token is invalid or has expired.');
return res.redirect('back');
};
user.password = req.body.password;
user.resetPasswordToken = undefined;
user.resetPasswordExpires = undefined;
user.save(function(err) {
req.logIn(user, function(err) {
done(err, user);
});
});
});
},
function(user, done) {
var smtpTransport = nodemailer.createTransport('SMTP', {
service: 'Gmail',
auth: {
user: 'harryandrew.dix#gmail.com',
pass: process.env.GMAIL_PASS
};
});
var mailOptions = {
to: user.email,
from: 'passwordreset#demo.com',
subject: 'Your password has been changed',
text: 'Hello,\n\n' +
'This is a confirmation that the password for your account ' + user.email + ' has just been changed.\n'
};
smtpTransport.sendMail(mailOptions, function(err) {
req.flash('success', 'Success! Your password has been changed.');
done(err);
});
};
], function(err) {
res.redirect('/');
});
});
// app.post('/add_item', function(req, res) {
// var item = new Item({
// owner: req.user.id,
// product_name: req.body.product_name,
// condition: req.body.condition,
// details: req.body.details,
// price: req.body.price
// });
// item.save(function(err) {
// if (err) {
// req.flash('error', 'Something went wrong, make sure you are signed in.')
// res.redirect('/add_item');
// } else {
// req.logIn(item, function(err) {
// res.redirect('/user_profile');
// });
// };
// });
// });
var server = app.listen(3000, function() {
var host = server.address().address;
var port = server.address().port;
console.log('Example app listening at http://%s:%s',host,port);
});
item.jade
include layout
html
block content
form(method='POST')
legend(style='font-family: Raleway; font-size: 30px;') Item Details
.form-group
label(for='product_name') Product Name
input.form-control(type='text', name='product_name', placeholder='include product name, brand, condition, colour etc.', required autofocus)
.form-group
label(for='condition') Condition
input.form-control(type='text', name='condition', placeholder='e.g. New, Used', required)
.form-group
label(for='image') Image
input.form-control(type='file', name='image')
.form-group
label(for='details') Details
textarea.form-control(name='details', cols='40', rows='5')
.form-group
label(for='price') Price
.input-group
.input-group-addon £
input.form-control(type='text', placeholder='Amount', required)
.input-group-addon .00
br
br
button#btnSubmit.btn.btn-primary(type='submit') Post Item
I think it's acting as form post and tries to reach app.post('/sell')
Change it:
button.btn.btn-primary(type='submit', href='/sell') Add Item
to:
a.btn.btn-primary(href='/sell') Add Item
also remove some parts of middleware and keep only these lines:
app.set('views', 'app/views');
app.set('view engine', 'jade');
app.set('port', process.env.PORT || 3000);
app.use(logger('dev'));
and then navigate in Your browser to /sell route, check if it's working.
if Yes - so problem with one of middlewares that we have deleted to check.
You should add a logger middleware and see what error the server gives when you try to go to that route. Another thing to try would be to rename the sell route and see if that works. That could indicate a conflict with another one of your routes, although it's not clear where this would be from looking at your code.