node.js emailing from contact me section - node.js

I just created a static portfolio bootstrap website as a practice and there is a contact me section at the bottom of the site where you can type in your name, phone number, email and some text. This website was created originally as a static one but after me watched a couple of youtube videos on how to sending email by using node.js and I tested it out in a separate project and the code worked. So I decided to add this functionality to this static website and I did, but the code I learned is no longer working. I am very new to node.js and now I think the whole idea could be wrong in the first place as I might need to have different folder structure / or environment set up at least to get this work at the very beginning and not just simply adding something on top of it, is that correct.
I have provided an image of my folder structure and my app.js file. The app.js has been placed in the public folder directory (as I found out after some research) and also added a link to html file for the html page to access to the JavaScript file. However, once I placed app.js inside the public folder, I kept getting errors when I run node.js app.js. It seems it not working anymore.
Furthermore, the code you have seen below is from a youtube video I followed where the contact form was the only thing it renders, however, in my case, the contact form is part of the html file and how do I render the form if the contact form is a part of a html file. Can anyone help me?
const express = require('express');
const bodyParser = require('body-parser');
const exphbs = require('express-handlebars');
const path = require('path');
const nodemailer = require('nodemailer');
const app = express();
// View engine setup
app.engine('handlebars', exphbs());
app.set('view engine', 'handlebars');
// Static folder
app.use('/public', express.static(path.join(__dirname, 'public')));
// Body parser middleware
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())
app.get('/', (req, res) => {
res.render('contact');
});
app.post('/send', (req, res) => {
const output = `
<p>You have a new contact request</p>
<h3>Contact Details</h3>
<ul>
<li>Name: ${req.body.name}</li>
<li>Email: ${req.body.email}</li>
<li>Phone: ${req.body.phone}</li>
</ul>
<h3>Message</h3>
<p>${req.body.message}</p>
`;
// create reusable transporter object using the default SMTP transport
let transporter = nodemailer.createTransport({
host: 'smtp.gmail.com',
port: 587,
secure: false, // true for 465, false for other ports
auth: {
user: 'jasonking4ever#gmail.com', // generated ethereal user
pass: 'senyang123' // generated ethereal password
},
tls: {
rejectUnauthorized: false
}
});
// setup email data with unicode symbols
let mailOptions = {
from: '"Contact Form" <jasonking4ever#gmail.com>', // sender address
to: 'syan19#live.cn', // list of receivers
subject: 'You have a new contact request', // Subject line
text: 'Hello world?', // plain text body
html: output // html body
};
// send mail with defined transport object
transporter.sendMail(mailOptions, (error, info) => {
if (error) {
return console.log(error);
}
console.log('Message sent: %s', info.messageId);
console.log('Preview URL: %s', nodemailer.getTestMessageUrl(info));
res.render('contact', { msg: 'Email has been sent' });
});
})
app.listen('3000', () => console.log('the server is starting...'))

Hey there your server file which i can see is app.js must me in the root directory(by root i mean in your folder root directory) not in public folder, the public folder is meant to serve public file(let say UI related file.). So remove your app.js from there and put in your folder root directory and run node.I hope that helps.

Related

Nuxt.js and Node.js simple form with nodemailer PROBLEM :(

I am new to Nuxt.js and Node.js. I would like to run a very simple contact form on a 'contact.vue' page. It works very well locally, but as soon as I do an 'npm run generate' to generate the files and upload all of this to an FTP it doesn't work anymore. I have an error in the console: "POST http://website.com/api/message 404 (Not Found)"
I use the POST method on my form with the action that points to 'api / message'. I am using axios in a method (on this same 'contact.vue' page :
async onSubmit (e) {
e.preventDefault()
await this.$axios.post('/api/message', {
name: this.contactForm.name,
firstname: this.contactForm.firstname,
})
.then((res) => {
// On clear le formulaire
this.contactForm.name = ''
this.contactForm.firstname = ''
})
.catch((err) => {
console.log(err)
})
}
I have in the root folder an 'api/' folder with inside 'index.js' and the code :
const app = require('express')()
const bodyParser = require('body-parser')
const nodemailer = require('nodemailer')
module.exports = { path: '/api', handler: app }
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())
app.post('/message', async (req, res) => {
const contenuFormulaireContact = `
<ul>
<li>Nom : ${req.body.name}</li>
<li>Prénom : ${req.body.firstname}</li>
</ul>
`
// NODEMAILER
const transporter = nodemailer.createTransport({
host: '',
port: 465,
secure: true,
auth: {
user: '',
pass: ''
}
})
const info = await transporter.sendMail({
from: '"Website's Name" <hello#website.com>', // sender address
to: 'myemail#website.com', // list of receivers
subject: `NEW MESSAGE : ${req.body.subject}`, // Subject line
text: '', // plain text body
html: contenuFormulaireContact // html body
})
console.log('Message sent: %s', info.messageId)
console.log('Preview URL: %s', nodemailer.getTestMessageUrl(info))
res.redirect(200, '/contact')
})
Inside the nuxt.config.js i have :
/*
** Nuxt.js modules
*/
modules: [
'#nuxtjs/pwa',
'#nuxtjs/axios'
],
/*
** Axios cfg
*/
axios: {
baseURL: '/'
},
/*
** Server middleware
*/
serverMiddleware: ['~/api/index.js'],
I'm sorry if for some of you this problem may seem very obvious but I'm completely stuck.
Thank you very much in advance if you take the time to help me.
Actually when you run npm run generate, the website becomes fully static and node doesn't run in the background anymore. This is why your code would works with npm run dev or npm run start since they runs node simultaneously.
I am facing the same issue. A static website is not able to send mail from the client. It has to be sent server-side. To make your code works, you either have to use a node.js server, use serverless functions solutions like AWS Lambda or Netlify functions which will executes the mail sender function or use an external REST API service like Formspree or 99inbound.
See https://stackoverflow.com/a/53560851/2610770.
I hope I helped you a bit!

How do I export a post request object in express Nodejs to another module

This code is returning a data object containing a user's form input exactly as I expect. I have used a variable contactFormInfo to contain that object and when I console.log(contactFormInfo) I get the object commented at the bottom of my code. My problem is how do I export this object into another module, mailer.js where I want to extract the information to use to send an email. As a newbie, I am stuck and any any help is highly appreciated.
const express = require('express');
const app = express();
// register view engine
app.set('view engine', 'ejs');
//Http listening app
app.listen(5000, ()=> console.log('Server is listenong on port 5000'));
//Middleware and static files
app.use(express.static('public'));
//Render Home Page
app.get('/', (req, res) => { res.render('index')});
app.use(express.urlencoded({ extended: true }));
//Receiving submit-form data through post request
app.post('/', (req, res)=> { let contactFormInfo = req.body;
res.redirect('/');
res.end();
console.log(contactFormInfo);
});
//OUTPUT WHEN I console.log(contactFormInfo);
/*
{
name: 'John Doe',
email: 'jdoe#outlook.com',
subject: 'Brand development',
mobile: '0722200000',
message: 'Please call or email'
};
*/
You will need to create a function with the logic of sending emails based on parameters it receives and import this function where your route logic is present.
and invoke the function in your mailer.js from the route with your contactFormInfo variable.
You can use this approach :-
Create an Email function in a separate file and export it to your app.js.
Note here I am using sendgrid API and ES6 import/export syntax.You can use your own api for sending API and normal import and export syntax.
import sgMail from '#sendgrid/mail'
sgMail.setApiKey(process.env.SENDGRID_API_KEY)
const sendWelcomeEmail = (userEmail, nameOfUser) => {
sgMail.send({
to: userEmail,
from: 'example#gmail.com',
subject: 'Welcome to Task Manager Application',
text: `Hi There!!! How are you ${nameOfUser}?.`
//html: '<strong>and easy to do anywhere, even with Node.js</strong>',
});
}
export {
sendWelcomeEmail,
};
import it in your app.js.
import sendWelcomeEmail from 'path/to/email/function/module'
Then inside app.js
Change your router like this
app.post('/', (req, res)=> { let contactFormInfo = req.body;
res.redirect('/');
res.end();
sendWelcomeEmail(contactFormInfo.name,contactFormInfo.email) //pass any properties you want to use in your mail.
console.log(contactFormInfo);
});

I cannot make a mail system with Nodemailer

I have been creating the system for several hours. I almost put the project into an end, but somehow I cannot receive any emails after filling the form. Does anyone know what is the cause of this problem ??
First, I installed node.js, then nodemon. I have four main files and a folder in the project folder - app.js, package-lock.json, contact.handlebars, package.json and node_module.
the code below is app.js
const express = require("express");
const bodyParser = require("body-parser");
const exphbs = require("express-handlebars");
const path = require("path");
const nodemailer = require("nodemailer");
const app = express();
// view engine setup
app.engine("handlebars", exphbs());
app.set("view engine", "handlebars");
// Static folder
app.use("/public", express.static(path.join(__dirname, "public")));
// Body Parser Middleware
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.get("/", (req, res) => {
res.render("contact", { layout: false });
});
app.post("/send", (req, res) => {
const output = `
<p>You have a new contact request</p>
<h3>Contact Details</h3>
<ul>
<li>Name: ${req.body.name}</li>
<li>Company: ${req.body.company}</li>
<li>Email: ${req.body.email}</li>
<li>Phone: ${req.body.phone}</li>
</ul>
<h3>Message</h3>
<p>${req.body.message}</p>
`;
async function main() {
// Generate test SMTP service account from ethereal.email
// Only needed if you don't have a real mail account for testing
let testAccount = await nodemailer.createTestAccount();
// create reusable transporter object using the default SMTP transport
let transporter = nodemailer.createTransport({
host: "I PUT 1ST SERVERNAME HERE OF HOSTGATOR",
port: 587,
secure: false, // true for 465, false for other ports
auth: {
user: "MY 1ST EMAIL ACCOUNT", // generated ethereal user
pass: "********" // generated ethereal password
},
tls: {
rejectUnauthorized: false
}
});
// send mail with defined transport object
let info = await transporter.sendMail({
from: '"Nodemailer Contact" <MY 1ST EMAIL ACCOUNT>', // sender address
to: "MY SECOND EMAIL ACCOUNT", // list of receivers
subject: "Node Contact Request", // Subject line
text: "Hello world?", // plain text body
html: output // html body
});
console.log("Message sent: %s", info.messageId);
console.log("Preview URL: %s", nodemailer.getTestMessageUrl(info));
res.render("contact", { layout: false }, { msg: "Email has been sent" });
}
main().catch(console.error);
});
app.listen(3000, () => console.log("server started..."));
Ethereal's test SMTP service doesn't send the emails. From their website:
It's a completely free anti-transactional email service where messages never get delivered.
It looks like it lets you view a preview of the sent mail to check your application is working correctly, but to actually send email you need to set up a real SMTP server. You can get SMTP credentials for sending transactional mail from applications from various companies such as SendGrid and Mailgun.

Mailgun - Unauthenticated email from guest.com

I have mailgun setup in my node.js using nodemailer and I cannot get it to send emails when I test my route using my REST client. When I directly write the code into the server file, the email sends right away when the server starts.
However, when I write the email api in an app.post and test it with a REST client the email fails on the mailgun side and gets rejected by google??? This is only my assumption because of the error code I am getting.
Server response: 550 5.7.1 Unauthenticated email from guest.com is not
accepted due to domain's 5.7.1 DMARC policy. Please contact the administrator
of guest.com domain if 5.7.1 this was a legitimate mail. Please visit 5.7.1
https://support.google.com/mail/answer/2451690 to learn about the 5.7.1 DMARC
initiative. s12-v6si3013316qtg.362 - gsmtp
I've followed the link provided and the documentation says to check with the domain server. I do not understand why I am getting this error because I already authenticated my gmail within mailgun.
I've also tried switching to directly using the mailgun-js middleware. Found three different mailgun-js api from mailgun.com, mailgun-js on github, and mailgun-js on npmjs.com. Got the same error as above.
At a loss. Don't know what to do.
My nodemailer code:
const express = require('express');
const nodemailer = require('nodemailer');
const path = require('path');
const bodyParser = require('body-parser');
const app = express();
const port = 3000;
app.use(bodyParser.json());
app.use(express.static(path.join(__dirname, 'dist')));
app.post('/email', (req, res) => {
let transporter = nodemailer.createTransport({
host: 'smtp.mailgun.org',
port: 587,
secure: false, // true for 465, false for other ports
auth: {
user: 'postmaster#sandboxc8f2ecf64f364ca6ad740e658485c557.mailgun.org',
pass: 'my API key here'
},
tls: {
rejectUnauthorized: false
}
});
// setup email data with unicode symbols
let mailOptions = {
from: req.body.from, // sender address
to: 'cu0ngpitt#gmail.com', // list of receivers
subject: 'Someone wrote you from your Online Resume!', // Subject line
text: req.body.messge, // plain text body
};
// send mail with defined transport object
transporter.sendMail(mailOptions, (error, info) => {
if (error) {
return console.log(error);
}
console.log('Message sent: %s', info.messageId);
console.log('Preview URL: %s', nodemailer.getTestMessageUrl(info));
});
});
app.get('/', (req, res) => {
res.send('Hello world');
});
app.listen(port, () => {
console.log('Server running on port ' + port);
})
Mailgun responded to my ticket and said due to DMARC security, I am only allowed to send an email with the same domain as my mailgun account.
Since I had a free mailgun account. I had to change my sender address to my free mailgun address, which was postmaster#sandbox"some long string".mailgun.org
If using nodemailer, you can leave off the sender email or hard code it in.
If using mailgun-js, you have to hard code it in.
My old code:
// setup email data with unicode symbols
let mailOptions = {
from: req.body.from, // sender address
to: 'cu0ngpitt#gmail.com', // list of receivers
subject: 'Someone wrote you from your Online Resume!', // Subject line
text: req.body.messge, // plain text body
};
Corrected code:
// setup email data with unicode symbols
let mailOptions = {
postmaster#sandbox"some long string".mailgun.org, // sender address
to: 'cu0ngpitt#gmail.com', // list of receivers
subject: 'Someone wrote you from your Online Resume!', // Subject line
text: req.body.messge, // plain text body
};

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!! :)

Resources