I'm using express to send email by nodemailer module.
my code is following:
app.post('/', (req, res) => {
const output = `
<p>You have new one contact request</p>
<h3>Contact Details</h3>
<ul>
<li>Name:${req.body.name}</li>
<li>Email:${req.body.email}</li>
</ul>
<h3>Message</h3>
<p>${req.body.message}</p>
`;
// create reusable transporter object using the default SMTP transport
let transporter = nodeMailer.createTransport({
host: "mail.gmail.com",
port: 587,
secure: false, // true for 465, false for other ports
auth: {
user: 'mymail#gamil.com', // generated ethereal user
pass: '2020' // generated ethereal password
},
tls: {
rejectUnauthorized: false
}
});
// send mail with defined transport object
let mailOptions = {
from: "mymail#gamil.com", // sender address
to: "myfriend#gmail.com", // list of receivers
subject: "the subject", // Subject line
html: output // html body
};
transporter.sendMail(mailOptions, (error, info) => {
if (error) {
return console.log(error);
}
// , info.res
console.log("Message sent: %s", info.messageId);
console.log("Preview URL: %s", nodeMailer.getTestMessageUrl(info));
res.render('index', { msg: 'email has been sent' });
res.redirect('back');
});});
after clicking submit button, below code redirects to the Contact page:
res.redirect('back');
and then shows a message by this code:
res.render('index', { msg: 'email has been sent' });
now my aim is to instead of showing text by the forementioned code, showing the text in an alert box.
what I've tried for is like:
res.render('index','<script>alert("email has been sent")</script>');
but this doesn't work at all. by the way I'm not using ajax. then any idea or solution please?
Running a script directly from a server response like <script>doSomethingMaybeBad();</script> will not likely run in modern browsers as it could be used as an attack. At a glance anyway it doesn't seem like you're loading the full page <html>...</html> on the client side with these requests.
I recommend listening to ajax responses from the client side and showing an alert then. Without seeing all your code, here's a rough idea:
Replace:
res.render('index','<script>alert("email has been sent")</script>');
with a JSON response, or response in the same format as you had it before like this:
{ msg: 'email has been sent', status: 200 }
Then in your client code, replace something like this (just guessing what you have as you didn't post a client side example):
$('msg').html(response.msg)
With:
if (response.status === 200) {
alert(msg.msg);
// consider redirecting here if needed?
} else {
// show error, jQuery in this example however may be different for your current
$('msg').html(response.msg)
}
Related
I am experiencing an unexpected behaviour from nodemailer:
here is my code:
let transporter = nodemailer.createTransport({
host: 'outlook.office365.com',
auth: {
user: process.env.MAIL_USER, // generated ethereal user
pass: process.env.MAIL_PASS, // generated ethereal password
},
tls: {
rejectUnauthorized: false
}});
let info = transporter.sendMail({
from: '"Mark 👻"mymail#outlook.com',
to: "anothermailOfMine#gmail.com",
subject: "Hello ✔",
text: "Hello world?",
html: `<b>
<a href='http://localhost:3000/activate_user/${result._id}'>
<button>Activate
profile</button></a>
</b>`, // html body
});
transporter.sendMail(info, function (err, info) {
if (err) {
console.log(err);
res.json(err);
} else {
console.log(' mail sent');
res.json({success:true, message:''});
}})};
The sendMail method returns an error even if the mail is actually sent successfully, which means that the front-end never receives a positive response about the sending, that's the error i just mentioned:
Error: No recipients defined
at SMTPConnection._formatError
I wonder if I am doing something wrong.
I did find out what the problem was eventually:
the send mail method needed to be called in an asynchronous function.
The full error is EXTREMELY long, but here is a snippet:
TypeError [ERR_INVALID_ARG_TYPE]: The "chunk" argument must be of type string or an instance of Buffer or Uint8Array. Received an instance of Object
at PassThrough.Writable.write (_stream_writable.js:289:13)
at PassThrough.Writable.end (_stream_writable.js:583:10)
at Immediate._onImmediate (C:\Users\small\desktop\career-change\coding-round-2\portfolio-round1\recipe-app\projectv2\node_modules\nodemailer\lib
\mime-node\index.js:969:46)
at processImmediate (internal/timers.js:456:21) {
code: 'ERR_INVALID_ARG_TYPE'
}
This is my first time using nodemailer, or any emailing service for that matter. I originally started using it with my personal gmail account, then was getting the issue where gmail was blocking it because it was considered a less secure app. So I changed my email settings to allow access from less secure apps. And then I began getting this error.
I also tried using https://ethereal.email/ to autogenerate an email test account so that I could avoid using gmail, just in case that was the issue.
Here is my nodemailer code:
const express = require("express");
const router = express.Router();
const bodyParser = require("body-parser");
const nodemailer = require("nodemailer");
router.post("/contact", (req, res) => {
const output = {
msg: `You have a new contact request from ${req.body.name}`,
userEmail: req.body.userEmail,
subject: req.body.subject,
message: req.body.message,
};
console.log(res);
// create reusable transporter object using the default SMTP transport
let transporter = nodemailer.createTransport({
host: "smtp.ethereal.email",
port: 587,
auth: {
user: "ida.pollich73#ethereal.email",
pass: "JPtPvputy6n8JBzYe2",
},
});
let mailOptions = {
from: '"Nodemailer Contact" <mypersonalaccount#gmail.com>', // sender address
to: "differentpersonalaccount#gmail.com", // list of receivers
subject: "Node Contact Request", // Subject line
text: output, // plain text body
html: output, // html body
};
// send mail with defined transport object
transporter.sendMail(mailOptions, (error, info) => {
if (error) {
return console.log(error);
} else {
console.log(info);
}
res.send("email sent");
console.log("Message sent: %s", info.messageId);
// Message sent: <b658f8ca-6296-ccf4-8306-87d57a0b4321#example.com>
// Preview only available when sending through an Ethereal account
console.log("Preview URL: %s", nodemailer.getTestMessageUrl(info));
// Preview URL: https://ethereal.email/message/WaQKMgKddxQDoou...
});
});
module.exports = router;
Does anybody have any idea what the error means? Let me know if you need any more info.
In my case, i was a trying to send a wrong data type, so i convert the property html to string and was solved. How i was using next.js, the compiler has reading my html like a JSX element.
const mailOptions= {
from: email,
to: 'mail#gmail.com',
subject: `FORMULARIO DE: ${req.body.name}`,
text: req.body.message,
html: `<div>${req.body.message}</div>`,
}
i think the problem is the return. you must JSON.stringify(error) and get error from sendMail!
If you get some error like this:
TypeError [ERR_INVALID_ARG_TYPE]: The "chunk" argument must be of type string or an instance of Buffer. Received an instance of Object
at validChunk (_stream_writable.js:281:10)
at PassThrough.Writable.write (_stream_writable.js:316:21)
at PassThrough.Writable.end (_stream_writable.js:585:10)
at Immediate._onImmediate (/home/ajwebmaker/lsoftweb/node_modules/nodemailer/lib/mime-node/index.js:977:46)
at processImmediate (internal/timers.js:461:21) {
code: 'ESTREAM',
command: 'API'
}
You should add the following line like this:
<div>Name:${req.body.message}</div>
<div>Email${req.body.message}</div>
Add the HTML multiple time as you need to send messages to email.
the result looks like this:
const mailOptions= {
from: email,
to: 'mail#gmail.com',
subject: `FORMULARIO DE: ${req.body.name}`,
text: req.body.message,
html: `<div>Name:${req.body.message}</div><div>Email${req.body.message}</div>`
}
I have set up an email server on my host. It's basically a SMTP server that listens on port 25.
const recvServer = new SMTPServer({
requireTLS: true,
authOptional: true,
logger: true,
onConnect(session, callback) {
return callback();
},
onMailFrom(address, session, callback) {
console.log('from', address, session);
return callback();
},
onData(stream, session, callback) {
console.log('new msg');
let message = '';
stream.on('data', chunk => {
message += chunk;
});
stream.on('end', () => {
callback(null, 'Message queued');
simpleParser(message)
.then(parsed => {
console.log(parsed);
// here I wish to forward the message to outside gmail addresses
})
.catch(err => {
console.log(ee)
});
});
}
});
recvServer.listen(25);
recvServer.on('error', err => {
console.log(err.message);
});
It works fine for receiving emails from outside, like gmail etc.
But I want to be able to send emails outside also, or forward emails that I receive to some gmail addresses.
I know that I can do that using Gmail SMTP servers, but then I need an gmail account and password.
I want to be able to send email with my own server, just like yahoo sends mail to gmail using their own server not gmail accounts :)
You need a MTA (Mail Transfer Agent) in order to send an email.
So the popular options is: Postfix, here a guid how to setup postfix on ubuntu: https://help.ubuntu.com/community/Postfix
Or you can spin up a docker container like: https://hub.docker.com/r/bytemark/smtp/
Then you can use nodemailer to send emails through postfix or docker instance.
And if you want there is a full stack docker image all batteries included: https://github.com/tomav/docker-mailserver
Technically you can use NodeMailer for sending emails.
"use strict";
const nodemailer = require("nodemailer");
// async..await is not allowed in global scope, must use a wrapper
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: "smtp.ethereal.email",
port: 587,
secure: false, // true for 465, false for other ports
auth: {
user: testAccount.user, // generated ethereal user
pass: testAccount.pass // generated ethereal password
}
});
// send mail with defined transport object
let info = await transporter.sendMail({
from: '"Fred Foo 👻" <foo#example.com>', // sender address
to: "bar#example.com, baz#example.com", // list of receivers
subject: "Hello ✔", // Subject line
text: "Hello world?", // plain text body
html: "<b>Hello world?</b>" // html body
});
console.log("Message sent: %s", info.messageId);
// Message sent: <b658f8ca-6296-ccf4-8306-87d57a0b4321#example.com>
// Preview only available when sending through an Ethereal account
console.log("Preview URL: %s", nodemailer.getTestMessageUrl(info));
// Preview URL: https://ethereal.email/message/WaQKMgKddxQDoou...
}
main().catch(console.error);
As Sohail mentioned in the above answer you can use NodeMailer (https://nodemailer.com/about/) and its fairly easy. Below is a simple code snippet of using it. In addition there are other services that provided free tiers if you are looking for fancier services(examples are SendGrid (https://sendgrid.com/)).
async function sendemail(email, host , email_body) {
let transporter = nodemailer.createTransport({
host: "mail.example.com.au",
port: 465,
secure: true, // true for 465, false for other ports
auth: {
user: "test#example.com.au", // generated ethereal user
pass: "email_password" // generated ethereal password
}
});
let emailBody = email_body // This is the body of your email which is more or less a String
let info = await transporter.sendMail({
from: '" Name of sender" <test#example.com.au>', // sender address
to: email, // list of receivers
subject: "Email Subject", // Subject line
text: emailBody, // plain text body
// html: // html body
});
console.log("Message sent: %s", info.messageId);
return true;
}
In order to send email, you need an email client, not a server. Writing the client is usually easier than writing the server, so you could do that. If you don't want to write your own, you could use an MTA (like Postfix), which will contain both a client and a server.
You can solve this function by creating an account in SendGrid and then using its Node.js api to send emails.
These are the steps:-
npm install #sendgrid/mail
And then use this following code snippet :-
const mailer = require('#sendgrid/mail');
mailer.setApiKey(<YOUR_SENDGRID_API_KEY>);
const message = {
to: 'xyz#gmail.com',
from: 'abc#gmail.com',
subject: 'hello world',
text: 'hello world'
};
mailer.send(message);
You can get more samples and documentation in their Github repo.
I know there are many posts like this here, but I couldn't find any information that would solve my issue. So I tried using both nodemailer and emailjs.
I have this code:
This is for nodemailer
var nodemailer = require('nodemailer');
nodemailer.createTestAccount((err, account) => {
if (err) console.log(err);
// create reusable transporter object using the default SMTP transport
var transporter = nodemailer.createTransport({
host: "smtp.Hotmail.com", // Just Hotmail doesn't work either
// port: 587,
auth: {
user: 'xxx#outlook.com',
pass: 'xxx'
}
});
// setup email data with unicode symbols
let mailOptions = {
from: `${req.body.fullName} ${req.body.email}`, // sender address
to: 'alexander.ironside#mygeorgian.ca', // list of receivers
subject: 'Email from SMWDB contact form', // Subject line
html: `<h4>Name: ${req.body.fullName}</h4>
<h4>Company: ${req.body.company}</h4>
<h4>Phone: ${req.body.phone}</h4>
<p>Message: ${req.body.message}</p>`
};
// send mail with defined transport object
transporter.sendMail(mailOptions, (error, info) => {
if (error) {
return console.log(error);
}
console.log('Message sent: %s', info.messageId);
// Preview only available when sending through an Ethereal account
console.log('Preview URL: %s', nodemailer.getTestMessageUrl(info));
// Message sent: <b658f8ca-6296-ccf4-8306-87d57a0b4321#example.com>
// Preview URL: https://ethereal.email/message/WaQKMgKddxQDoou...
});
});
And this for emailjs
var email = require("emailjs");
var server = email.server.connect({
user: "xxx#outlook.com",
password: "xxx",
host: "smtp-mail.outlook.com",
tls: {ciphers: "SSLv3"}
});
var message = {
text: `Test`,
from: `${req.body.fullName} <${req.body.email}>`,
to: `Alex <alexander.ironside#mygeorgian.ca>`, // list of receivers
// cc: "else <else#your-email.com>",
subject: 'Email from SMWDB contact form', // Subject line
attachment:
[
{
data: `
<h4>Name: ${req.body.fullName}</h4>
<h4>Company: ${req.body.company}</h4>
<h4>Phone: ${req.body.phone}</h4>
<p>Message: ${req.body.message}</p>`
, alternative: true
},
]
};
// send the message and get a callback with an error or details of the message that was sent
server.send(message, (err, message) => {
console.log(err || message);
});
The problem I think is that as host both docs say something like this: smtp.your-email.com, meanwhile all code examples say this: host: "Hotmail". What's the correct way?
I don't really care which package I'm using.
I have to use Hotmail/Yahoo and cannot use Gmail (Too many accounts activated with one phone number)
Now to the errors:
Emailjs throws this:
{ Error: bad response on command '
.': 5.2.0 STOREDRV.Submission.Exception:SendAsDeniedException.MapiExceptionSendAsDenied; Failed to process message due to a permanent exception with message Cannot submit message. and then there is a lot of numbers and a callback trace.
Nodemailer throws this:
{ Error: getaddrinfo ENOTFOUND smtp.Hotmail.com smtp.Hotmail.com:587
at errnoException (dns.js:50:10)
at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:92:26)
code: 'ECONNECTION',
errno: 'ENOTFOUND',
syscall: 'getaddrinfo',
hostname: 'smtp.Hotmail.com',
host: 'smtp.Hotmail.com',
port: 587,
command: 'CONN' }
I used to do this in PHP and have no idea why it's so complicated with Node, but I guess there must be a reason.
I asked a friend to create a Gmail account and it worked right away. If you hit the same problem, don't bother with anything else. Just use Google.
That's the transporter code that worked for me
var transporter = nodemailer.createTransport({
host: "smtp.gmail.com", // hostname
auth: {
user: 'xxx#gmail.com',
pass: 'xxx'
}
});
I know how to send mail using nodemailer but I am using email credentials of that, but I don't want to use that. Is there any other method of sending mails.
My nodemailer code snippet is
var nodemailer = require('nodemailer');
// Not the movie transporter!
var transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: 'vikaskohli#email.com', // Your email id
pass: 'password' // Your password
}
});
module.exports =
{
sendEmail: function sendMail(varhtml,vartext, varsubject,varfrom, varfrom_name,varto, varto_name, reply_to_email ) {
//setup e-mail data with unicode symbols
var mailOptions = {
from: varfrom_name, // sender address
// to: ['vikaskohli#email.com','vikaskohli1#email.com'], // list of receivers
// to: ['vikaskohli#email.com,vikaskohli1#email.com'], // list of receivers
// to: 'vikaskohli#email.com','vikaskohli1#email.com', // list of receivers
to: varto, // list of receivers
subject: varsubject, // Subject line
text: vartext, // plaintext body
html: varhtml // html body
};
console.log(mailOptions);
// send mail with defined transport object
transporter.sendMail(mailOptions, function (error, info) {
if (error) {
return console.log(error);
}else{
return console.log(info);
}
});
}
}
In the above code, also I don't change my sender name. If I want to send from other mail like
vikaskohli3#gmail.com
but it automatically send from that mail for which I have use credentials here
vikaskohli#email.com
Also I tried using sendmail npm, they don't need any credentials but it send mail in the spam folder
My sendmail code snippet
var sendmail = require('sendmail')({silent: true})
sendmail({
from: 'vikaskohli#email.com',
to: 'vikaskohli#email.com,vikaskohli1#email.com',
subject: varsubject, // Subject line
html: varhtml,
attachments: [
]
}, function (err, reply) {
console.log(err && err.stack)
console.dir(reply)
});
I use sendmail like your bottom code, and it works fine for me. Perhaps the reason it's going to spam is because your settings in the email provider. Most likely the email you chose as sender (#email.com) seems like a spam to that service provider or your settings.