Cloud Functions using Nodemailer, Email sent but never arrives - node.js

I am using Google Cloud Functions to send E-Mail via Nodemailer, the mails are authenticated via Oauth2. It seems to work without any problems, the emails get sent and are also shown in the sent e-mails of my gmail account, but they actually never arrive at my other email address... Does someone know why?
This is my Code
const mailTransport = nodemailer.createTransport({
name: "gmail.com",
host: "smtp.gmail.com",
port: 465,
secure: true,
auth: {
type: "OAuth2",
user: gmailEmail,
pass: gmailPassword,
clientId: clientid,
clientSecret: clientsecret,
refreshToken: clientrefreshtoken,
accessToken: clientaccesstoken,
expires: 3599,
},
});
exports.submit = functions.https.onRequest((req, res) => {
const corsMiddleware = cors(corsOptions);
corsMiddleware(req, res, () => {
if (req.method !== "POST") {
return;
}
const mailOptions = {
from: req.body.email,
replyTo: req.body.email,
to: "myemail#gmx.at",
subject: `Absender: ${req.body.email}`,
html: req.body.message,
};
mailTransport.sendMail(mailOptions);
res.status(200).send({isEmailSend: true});
});
});
Thanks in Advance
Update!
Somehow i get some e-mails really late, but not all of them. More like 1 out of 10 and i also got this in my Mail inbox:
The recipient server did not accept our requests to connect.
Learn more at https://support.google.com/mail/answer/7720 [mx00.emig.gmx.net. 212.227.15.9: 421-gmx.net (mxgmx017)
Nemesis ESMTP Service not available 421-Service unavailable 421-Reject due to policy restrictions.
421 For explanation visit https://postmaster.gmx.net/en/error-messages?ip=209.85.222.194&c=sp ] [mx01.emig.gmx.net. 212.227.17.5: 421-gmx.net (mxgmx114)
Nemesis ESMTP Service not available 421-Service unavailable 421-Reject due to policy restrictions.
421 For explanation visit https://postmaster.gmx.net/en/error-messages?ip=209.85.222.196&c=sp ]

So after 2 days of trying i think the problem has nothing to do with my code....
Seems to be a problem with gmx servers, maybe i am on any blacklist? i dont know, account is new actually...
Nevermind sending it to my private email from my domain worked.

It is maybe not the reason of your problem, but you should wait that the asynchronous sendMail() execution is completed before sending back the response. If you don't do that you indicate to the Cloud Function platform that it can clean up the instance running your Cloud Function, without waiting for the asynchronous task to be completed.
exports.submit = functions.https.onRequest((req, res) => {
const corsMiddleware = cors(corsOptions);
corsMiddleware(req, res, () => {
if (req.method !== "POST") {
return;
}
const mailOptions = {
from: req.body.email,
replyTo: req.body.email,
to: "myemail#gmx.at",
subject: `Absender: ${req.body.email}`,
html: req.body.message,
};
mailTransport.sendMail(mailOptions)
.then(() => {
res.status(200).send({isEmailSend: true});
})
});
});

Related

Nodemailer - massive delay or missing emails in production

I currently have a site using Nodemailer & Gmail that works fine in my local development environment - any email sends instantly to the desired address.
Sadly, in production, only the admin notifications are being sent and the user ones are taking a very long time to deliver or not delivering at all. Ones that have arrived successfully took around 1 hour. The receiving email for admin emails is of the same domain as the URL of the website which makes me consider whether it's a domain verification issue. Only external recipients seem to get the delay.
My code is as follows:
const nodemailer = require('nodemailer')
const gmailUser = process.env.GMAIL_USER
const gmailPass = process.env.GMAIL_PASS
const appTitle = process.env.APP_TITLE
const receivingEmail = process.env.MAIL_RECEIVE
const smtpTransporter = nodemailer.createTransport({
host: 'smtp.gmail.com',
port: 465,
secure: true,
auth: {
user: gmailUser,
pass: gmailPass
}
})
const emailConfirmation = (userEmail) => {
const userMailOptions = {
from: appTitle,
to: userEmail,
subject: `${appTitle} - User Confirmation`
text: 'User Confirmation'
}
const adminMailOptions = {
from: appTitle,
to: receivingEmail,
subject: `${appTitle} - Admin Confirmation`,
text: 'Admin Confirmation'
}
Promise.all([
smtpTransporter.sendMail(userMailOptions),
smtpTransporter.sendMail(adminMailOptions)
])
.then((res) => { return true })
.catch((err) => { console.log("Failed to send email confirmations: ", err); return false })
}
I then call the function in a POST handler as follows:
emailConfirmation(user.email)
Am I doing something wrong in my code, or is this likely to be some sort of domain verification error?
I ended up deciding to switch to a different mail provider and have since had no issues.

Nodemailer with E-Mail Templating working locally but not in AWS Lambda environment

I am developing a small webapp that has user accounts. So I want to send E-Mails regarding their registration and E-Mail Address Confirmation.
I am using the Serverless Framework with Express and Node.js as well as Nodemailer with email-templates.
here is the mailer.js function to send a confirmation email:
function sendConfirmation (name, address) {
const transporter = nodemailer.createTransport({
host: 'smtp.strato.de',
port: 465,
secure: true,
auth: {
user: process.env.STRATO_USER,
pass: process.env.STRATO_PASSWORD,
}
});
const email = new Email({
transport: transporter,
send: true,
preview: false,
});
console.log("Sending Email");
email.send({
template: 'confirmation',
message: {
from: 'company',
to: address,
},
locals: {
fname: name,
}
}).then(() => console.log('email has been sent!'));
}
module.exports = {
sendRegister,
sendConfirmation
};
And here is the code of the route. I look for the user in the database and update him to be confirmed. Then I try to send the email.
router.post("/confirmation", async (req, res) => {
userId = req.body.userId;
let userUpdated = false;
let updatedUser;
updatedUser = await User.findByIdAndUpdate({_id: userId}, {"confirmed": true}, function (err, result) {
if(err){
res.send(err)
}
else{
userUpdated = true;
}
});
if (userUpdated) {
await sendConfirmation(updatedUser.name, updatedUser.email);
res.json({error: null, data: "User confirmed"});
}
});
If I test this with app.listen on localhost I receive the E-Mail without any problems. As soon as I deploy it to AWS with Serverless, the user gets updated in the DB, but the E-Mail is not send. It seems that Lambda does not wait until the promise of the email.send() is there? I also tried to explicitly allow the Lambda function to communicate with port 465 on outbound traffic. No luck.
In the logs of the Lambda function no error is shown, but also no confirmation of the sent email.
Has anyone an idea what I am missing? Thank you very much!
EDIT 1:
I just found out, that if I use await sleep(2000) with an according function
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
right after calling the sendConfirmation function and it works without problems. It seems, that the sendConfirmation function will not wait for the promise of email.send. Any idea how to solve this? I am fairly new to promises.
Thanks in advance!

Nodemailer "connect ETIMEDOUT" with custom domain

I'm making a forgot password backend route in Node.js and I'm attempting to use nodemailer to send the email from a custom domain I purchased from namecheap.com, along with the email domain. I'm not sure if it's a problem with the host, the port/security, or the auth. However, when I change the host it gives a a ECONREFUSED error instead so I believe that part is working. My firewall is (as far as I can tell) disabled and I restarted, however it is harder to tell because Norton Antivirus controls it.
This is my code, taken from a router.get route in my back-end.
The full error is "connect ETIMEDOUT" then an ip address with :587 at the end.
const transporter = createTransport({
host: 'axotl.com',
port: 587,
secure: false,
auth: {
user: config.get('emailUser'),
pass: config.get('emailPass')
}
});
let resetLink = '';
let authToken = '';
await jwt.sign({ email: req.params.email }, config.get('JWTSecret'), { expiresIn: 10800000 }, (err, token) => {
if (err) throw err;
authToken += token;
})
resetLink = await `${config.get('productionLink')}/recipients/resetpassword/${authToken}`
console.log(`resetlink : ${resetLink}`)
const mailOptions = {
from: '"Axotl Support" <support#axotl.com>',
to: req.params.email,
subject: "Forgot Password",
text: `Hello ${req.name},\n\nHere is the password reset link you requested (expires in 3 hours): ${resetLink}\nIf you did not request this, please notify us at http://axotl.com/support\n\nThanks!\n-Axotl Support`
}
try {
console.log('trycatch entered')
// const verified = await transporter.verify()
// console.log(`verified : ${verified}`)
const res = await transporter.sendMail(mailOptions)
console.log('email completed')
console.log(res)
res.json({ msg: "email sent" })
} catch (err) {
console.error(err.message);
res.status(500).send("Server Error")
}
Turns out I was using the wrong host domain-- the service doesn't directly host the email domain on the website. I don't know enough about this specific section. I changed it to the email host and it worked.

Emails sent via nodemailer from my server come through as spam: (unknown sender)

First time using Node and working with email configuration. I downloaded this application from here, it works (uses mustache.js to generate templates for the emails), but the test email ends up in my gmail spam.
from: via vps1234.inmotionhosting.com
to: thisisme#gmail.com
date: Tue, Aug 8, 2017 at 5:30 PM
subject: Thanks! and review your experience
mailed-by: vps1234.inmotionhosting.com
security: Standard encryption (TLS) Learn more
-
var nodemailer = require('nodemailer');
let transporter = nodemailer.createTransport({
service: ' ',
secure: false,
port: 25,
auth: {
user: 'thisisme#mydomain.com',
pass: 'password1234'
},
tls: {
rejectUnauthorized: false,
}
}),
EmailTemplate = require('email-templates').EmailTemplate,
path = require('path'),
Promise = require('bluebird');
let users = [
{
name: 'John',
note: 'I found your purse',
email: 'recipient#gmail.com',
}
];
function sendEmail (obj) {
return transporter.sendMail(obj);
}
function loadTemplate (templateName, contexts) {
let template = new EmailTemplate(path.join(__dirname, 'templates', templateName));
return Promise.all(contexts.map((context) => {
return new Promise((resolve, reject) => {
template.render(context, (err, result) => {
if (err) reject(err);
else resolve({
email: result,
context,
});
});
});
}));
}
loadTemplate('welcome', users).then((results) => {
return Promise.all(results.map((result) => {
sendEmail({
to: result.context.email,
from: 'Me :)',
subject: result.email.subject,
html: result.email.html,
text: result.email.text,
});
}));
}).then(() => {
console.log('Yay!');
});
This is Nodemailer boilerplate, which I tested also on my server, and it worked correctly, and the email did not get flagged:
var nodemailer = require('nodemailer');
let transporter = nodemailer.createTransport({
service: ' ',
secure: false,
port: 25,
auth:{
user: 'thisisme#mydomain.com',
pass: 'password1234'
},
tls: {
rejectUnauthorized: false,
}
});
let helperOptions = {
from: '<thisisme#mydomain.com>',
to: 'recipient1234#gmail.com',
};
transporter.sendMail(helperOptions, (error, info) =>{
if(error){return alert(error);}
console.log("sent" . info);
})
A message being marked as spam is not so much a function of the code that generated it but of a few other things such as:
the actual content (text, links etc)
the domain it came from
The first issue is just something you have to play with. There are services such as MailMonitor and others that help you tweak your content to see how gmail and others handle it. Wording, HTML vs plain text, links vs none, etc all play a part.
As far as the domain, you'll want to setup your SPF (Sender Policy Framework) and DKIM entries to essentially validate your domain as a proper sender. The "unknown sender" is most likely a missing SPF record.
For SPF here's an article.
For DKIM here's another
Note that I just googled for this - they seemed like good articles but I am sure there are other great sources.
The gist of it is that you'll want to create a couple of TXT entries in your DNS. There are tools such as SPF generators to help you with this. It's not as complex as it may sound.
Once that is done you might still end up in spam but it will certainly help. You can experiment with services such as Amazon SES and SendGrid which might provide better sending "validity" than your current SMTP server.

Gmail refresh tokens, xoauth2 and general informations

I started using nodejs and nodemailer a week ago and I've got some questions about Gmail oauth.
I've set my client ID my secret ID pretty easily but now I'm stuck on a "problem", I'm using gmail refresh tokens for authorizing my botmailer to send newsletter emails, being said it seems that when the token expires my bot is no more authorized and I cannot send emails anymore.
Is there a way I can automatically update the refresh token in my code ?
This is what I got so far, thanks in advance!
var transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
xoauth2: xoauth2.createXOAuth2Generator({
user: 'mybotemail',
clientId: 'myclientid',
clientSecret: 'mysecretid',
refreshToken: 'myrefreshtoken',
accessToken: 'myaccesstoken'
})
}
});
var mailOptions = {
from: "myemailverifiedabove",
to: user,
subject: "Hello world",
generateTextFromHTML: true,
html: "<b>Hello world</b>"
};
transporter.sendMail(mailOptions, function(error, response) {
if (error) {
console.log(error);
} else {
console.log(response);
}
transporter.close();
});
EDIT: Gmail also suspended my account once without even saying why, if some of you does know why, I would appreciate it.

Resources