I'm using nodemailer to allow users to contact me via email. After submitting the form data, I'm redirected to my homepage (which is what I want), but if I try to refresh the page I get an alert message that says:
Confirm Form Resubmission
The page that you're looking for used information that you entered.
Returning to that page might cause any action you took to be repeated.
Do you want to continue?
I think this has something to do with the user's data being cached, so is there a way around this? I don't want people sending me multiple emails by accident, and I don't want them annoyed with an alert box every time they refresh. Here's my controller function:
module.exports.contactMessage = function(req, res) {
// html message sent to my email
var output = `
<p>You have a new contact request</p>
<h3>Contact Details</h3>
<ul>
<li>Name: ${req.body.name + ' ' + req.body.surname}</li>
<li>Email: ${req.body.email}</li>
</ul>
<h3>Message:</h3>
<p>${req.body.message}</p>
`;
var from = req.body.email;
var to = 'example#example.com';
// create reusable transporter object using the default SMTP transport
let transporter = nodemailer.createTransport({
host: 'smtp.gmail.email',
service: "Gmail",
auth: {
user: 'example#example.com',
pass: 'password'
},
tls: {
rejectUnauthorized:false
}
});
// setup email data with unicode symbols
let mailOptions = {
from: from, // sender address
to: to, // list of receivers
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);
res.render('index', {msg: 'Your message has been sent'});
});
};
Usually appending a random integer to the end of the url will cause the browser to reload the page because it does not match exactly what is in cache.
For example, https://www.google.com?318973187678123 will load the same page as https://www.google.com but will force the browser to not load from cache.
Note however, this random integer needs change each reload to work, so generate a new random integer each reload.
Related
I just set up my glitch project with a contact form and im trying to get it to send an email to me when someone fills out the form. The issue that I am having is that the server logs in console that the message has been sent with no errors but I never receive the email. You can find the code at https://glitch.com/edit/#!/gamesalt-dev?path=packages%2FPOSTroutes.js%3A2%3A39 and the contact form can be found at https://gamesalt-dev.glitch.me/.
let account = {
user: "some.name#ethereal.email",
pass: "************"
}
let transporter = nodemailer.createTransport({
host: "smtp.ethereal.email",
port: 587,
secure: false,
auth: {
user: account.user,
pass: account.pass,
},
});
let mailOptions = {
from: `"Contact" <${account.user}>`,
to: "some.name#example.com",
subject: "New Contact!",
text: "Hello world",
html: "<b>Hello world</b>",
}
let info = await 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));
});
http://ethereal.email/
Ethereal is a fake SMTP service, mostly aimed at Nodemailer users (but not limited to). It's a completely free anti-transactional email service where messages never get delivered.
Instead, you can generate a vanity email account right from Nodemailer, send an email using that account just as you would with any other SMTP provider and finally preview the sent message here as no emails are actually delivered.
Even if not, the server logs in console that the message has been sent with no errors the message you get is that the SMTP server successfully accepted your mail and added it to the send queue, but that will not guarantee that it will be delivered. The receiving SMTP server could still reject it and send a bounce message back.
i am using for our project in company the nodemailer, its working perfectly
fine.
I am wondering if its possible to get user's info automatically from the post request. for example i need to get the html variable like this:
html: 'Hello i am ${request.username} i sent this email to you'
this is how i need my request looks like:
var transporter = nodemailer.createTransport({
host: 'servername.com',
port: 25,
debug: true,
logger:true,
secure: false,
});
// i need the mail options like the following
var mailOptions = {
from: 'MYEMAIL#COMPANYNAME.com', // sender address (who sends)
to: 'MYEMAIL#COMPANYNAME.com', // list of receivers (who receives)
subject: 'this email sent from ${request.username} ', // Subject line
text: 'Hello world ', // plaintext body
html: 'this email sent from ${request.username}'
};
// send mail with defined transport object
transporter.sendMail(mailOptions, function(error, info){
if(error){
return console.log(error);
}
What you are asking is not possible (atleast ethically) unless you have username and email mapping available. But still to add a personal touch to email you can use part before "#" i.e. take this email for instance "your_name#domain.com", you can send email as
${request.username} will be "your_name"
At the bottom of my personal page (1 page website) I have a contact form that sends a message to my database so I can read it later.
The problem is that if I don't redirect to anywhere, the page doesn't reload, which is what I want, but is searching for something and have a loading icon in the tab and eventually disconnects and show the "ECONNRESET" error from Cloud9.
If I do redirect back to /#contact (to the page and then down to the contact section), then it reloads the page, and that's not what I want to happen because of the site's functionality. It has some animations that load right after sending the message and the reload cancels them out and it looks terrible.
How do I make it so that the page doesn't have to reload after sending the message, meaning I don't have to redirect anywhere, but I also don't get the ECONNRESET error?
app.post("/", function (req, res){
// Retrieve form data
var name = req.body.name;
var email = req.body.email;
var subject = req.body.subject;
var message = req.body.message;
var newMessage = {name: name, email: email, subject: subject, message: message};
// Save new message to database
Message.create(newMessage, function (err, sendMessage) {
if (err) {
console.log(err);
} else {
console.log(sendMessage);
}
});
});
If you are not posting the form via AJAX, then you should redirect to the GET endpoint where your view is rendered. If you do not want to redirect, then at the very least you will need to have a res.render() call to render the correct view. The drawback to not redirecting is that if the user refreshes the page, they may get prompted to resubmit the form.
Message.create(newMessage, function(err, sendMessage){
if(err){
console.log(err);
} else {
console.log(sendMessage);
res.render('contact'); //change 'contact' to the name of the view you are rendering
}
});
I did some searching and I found a way to do it how I want it to work: no redirecting or reloading the page.
I removed the unnecessary error handling and console.log since all I need is for the form to send the data to my database so I can read it later.
app.post("/", function(req, res){
// Retrieve form data
var name = req.body.name;
var email = req.body.email;
var subject = req.body.subject;
var message = req.body.message;
var newMessage = {name: name, email: email, subject: subject, message: message};
// Save new message to database
Message.create(newMessage);
});
Apparently I need a Ajax/jQuery request, which looks like this:
$('form').submit(function(e){
e.preventDefault();
$.ajax({
url:'/',
type:'post',
data:$('form').serialize(),
success:function(){
//whatever you wanna do after the form is successfully submitted
}
});
});
Source to the answer I found (First answer)
I have followed the instructions on the nodemailer site to the letter, but OAuth2 for google service accounts simply does not work for me.
Either I get ECONN timeouts when setting "host" to mail.google.com or some combination of "401, user/pwd not accepted, can not create access token" errors when using smtp.gmail.com as the host.
I've used this as my template:
http://nodemailer.com/smtp/oauth2/#example-4
I've set up a service account: https://developers.google.com/identity/protocols/OAuth2ServiceAccount
I've enabled the gmail api.
I've created tokens that validate:
https://www.googleapis.com/oauth2/v1/tokeninfo
I have also tried the xoauth2 npm package to generate tokens and failed...
I also tried the answer in this question, but still no luck...
There seems to be an endless supply of answers for 3LO, but none that I've tried for 2LO that work. Now, having said all that.
var nodemailer = require("nodemailer");
var { google } = require("googleapis");
var accessToken;
var expires;
var key = require(“path/to/secrets.json");
var privateKey = key.private_key;
var jwtClient = new google.auth.JWT(key.client_email, null, key.private_key, ["https://mail.google.com/"], null);
jwtClient.authorize(function(err, tokens) {
if (err) {
return;
} else {
token = tokens
accessToken = tokens.access_token //this **IS** a valid token
expires = tokens.expiry_date
}
var transporter = nodemailer.createTransport({
host: "smtp.gmail.com",
port: 465,
secure: true,
auth: {
type: "OAuth2",
user: key.client_email, //I've also used my email here
serviceClient: key.client_id,
privateKey: privateKey,
accessToken: accessToken,
expires: expires,
},
});
var mailOptions = {
from: “me#here.com”
to: “me#there.com",
subject: "Ready",
text: “Really Ready"
}
transporter.sendMail(mailOptions, function(error, info) {
if (error) {
return;
}
console.log("Message %s sent: %s", info.messageId, info.response);
});
});
which generated the error:
535-5.7.8 Username and Password not accepted.
But as I mentioned, I've tried differing configurations and settings and gotten just as many different errors...
SO... Has anyone had success in using service accounts for 2LO using nodemailer?
I'm using node 9.5.0 and nodemailer ^4.6.0
I got it working (2021!), these were the steps:
Log in to console.- https://console.cloud.google.com/
Create a service account under the project.
Click on the new service account, go to permissions and add a member. You will use this member's email address when sending the request.
Create keys for the service account. - keys -> add key. https://console.cloud.google.com/iam-admin/serviceaccounts
Download your key file. You will get something like service-account-name-accountid.json. It will have all the information you need to get the code below running.
Delegate authority to your service account https://developers.google.com/identity/protocols/oauth2/service-account#delegatingauthority. Addhttps://mail.google.com/ as the scope.
Write some code like below:
const nodemailer = require('nodemailer');
const json = require('./service-account-name-accountid.json');
const sendEmail = async (email, subject, text) => {
try {
const transporter = nodemailer.createTransport({
host: 'smtp.gmail.com',
port: 465,
secure: true,
auth: {
type: 'OAuth2',
user: email, //your permissioned service account member e-mail address
serviceClient: json.client_id,
privateKey: json.private_key
}
});
await transporter.verify();
await transporter.sendMail({
from: json.service_email,
to: email, //you can change this to any other e-mail address and it should work!
subject,
text
});
console.log('success!');
return {
status : 200
}
} catch (error) {
console.log(error);
return {
status : 500,
error
}
}
}
sendEmail('your_permissioned_service_account_email_address#some_place.com, 'testing 123', 'woohoo!');
Why? Because one the default scopes on your credentials for OAuth 2.0 client IDs are these:
email <- Can only view email address
profile
openid
If you want to send email using node mailer it should include this scope:
https://mail.google.com/
and which is a sensitive scope, so google needs to verify it first else you will receive some delegation error messages.
Follow this verification process.
And add scope in the consent page
Or
Make sure you're an admin of the gsuite then give your service account access to sending email or an admin can give your service account access to sending email.
This guide will help. It's in Japanese just translate it to english.
Old thread, but I've got this working just now (after a lot of trying) so a few suggestions for anyone interested:
Enable the Gmail API in the Cloud Console
Use your 'normal' email address as the user (not the Service Account email)
Go here https://admin.google.com/ac/owl/domainwidedelegation and add your service client to the list. Here you will have to type in your client_id for the Client Name part and https://mail.google.com/ as the API scope. This last part was hard to find, but made it work for me in the end.
Also, I found this guide very helpful: Here you will have to type in your client_id for the Client Name part and https://mail.google.com/ as the API scope before pressing the Authorise.
I am working on an app with React as the base. I have created a registration page and want to send a verification code via email to the user once he registers. I have done the UI part, but have no idea on how to proceed and make it work. I have seen how emails are sent to the user upon registration in PHP, and want to implement the same in React.
Since you are using node, you'll be able to make use of the node mailer package. This allows you to send emails easily straight from node.
https://nodemailer.com/
Have a look at there site for all the details on how to get it setup!
Here is some psuedo code:
User.register(userDetails).then( (createdUser) => {
// Your user is created
// Now lets send them an email
var mailOptions = {
from: '"Info ?" <yoursite#yoursite.com>', // sender address
to: userDetails.email, // This can also contain an array of emails
subject: 'Thanks for registering with <your site name>',
// text: 'Hello world ?', // plaintext body
html: '<b>Some HTML here....</b>' // html body
};
// send mail with defined transport object
transporter.sendMail(mailOptions, function(error, info){
if(error){
return console.log(error);
}
console.log('Message sent: ' + info.response);
});
})