Emails are not sent out after deploying to Lamba function - node.js

I'm using Nodemailer and SES to send out mails from my application, it works perfectly locally but doesn't work once I deploy to Lambda function, it returns with a "Endpoint request timed out" error message after it exceeds the 30 seconds API gateway time limit.
Note: The Lambda function has all the permissions required to send out SES mails.
I thought SES was the problem and I decided to use gmail instead, I got the same result. Checking my cloudwatch logs I find this error:
2022-11-16T06:54:23.547Z 6d967bf2-0837-4bd8-ae5f-011842656d15 INFO Error: Connection timeout
at SMTPConnection._formatError (/var/task/node_modules/nodemailer/lib/smtp-connection/index.js:790:19)
at SMTPConnection._onError (/var/task/node_modules/nodemailer/lib/smtp-connection/index.js:776:20)
at Timeout.<anonymous> (/var/task/node_modules/nodemailer/lib/smtp-connection/index.js:235:22)
at listOnTimeout (node:internal/timers:559:17)
at processTimers (node:internal/timers:502:7) {
code: 'ETIMEDOUT',
command: 'CONN'
}
Here's my function for sending out the mails, I have modified it so many times, I thought I was the one not structuring it properly.
const transporter = nodemailer.createTransport ({
service: 'gmail',
host: 'smtp.gmail.com',
port: 587,
secure: true,
auth: {
user: config.REACT_APP_EMAIL,
pass: config.REACT_APP_EMAIL_PASS,
},
});
const sendOutMail = async (receiver, emailSubject, body) => {
return transporter.sendMail({
from: config.REACT_APP_EMAIL,
to: receiver,
subject: emailSubject,
text: body,
html: '<div> ' + emailSubject + '</div>',
})
.then( results => {
console.log("Success:", results);
return true
})
.catch ( error => {
console.log("Error:", error);
return false
})
}
All modifications of my function works locally, but none works after I deploy

Since your lambda function runs inside a VPC, make sure you have internet access on this VPC. Otherwise you need to create a VPC Endpoint for SES so that your lambda can make that API call.
Here is the documentation for reference:
https://docs.aws.amazon.com/ses/latest/dg/send-email-set-up-vpc-endpoints.html

Related

Error: Invalid greeting. response=421 Service not available: 421 Service not available

i tried using nodemailer to send emails from my outlook account to other accounts but i keep getting this error.
Error: Invalid greeting. response=421 Service not available: 421 Service not available
code: 'EPROTOCOL',
response: '421 Service not available',
responseCode: 421,
command: 'CONN'
Here is my code
const nodemailer = require("nodemailer");
module.exports = function OTP() {
// Sends otp link to and code to user
return new Promise((resolve, reject) => {
const transporter = nodemailer.createTransport({
service: "hotmail",
port: "25",
secure: true,
auth: {
user: process.env.EMAIL, //Outlook email
pass: process.env.EMAIL_PASSWORD,
},
tls: {
ciphers: "SSLv3",
},
});
transporter.sendMail(
{
from: process.env.EMAIL,
to: email,
subject: "Test",
text: `
`,
},
(err, info) => {
if (err) {
console.log(err);
return reject({ message: "An error has occurred" });
} else return resolve({ message: "Email sent" });
}
);
});
};
i tried changing the port and switching to gmail but i get the same error.
I had this same error but in nestjs and this is my solution that you can try.
First in my configuration I did not define a port and my secure was set to false, so port was default to 587. I was sending mail and everything was fine untill one day I started to get the same error as you are getting now. so here is my fix
I use telnet to test my connection to the mail server:
a. Open terminal and type: telnet your_domain 587. eg
telnet smtp.sendgrid.net 587
I got 421 Service not available
I change secure to true which will now default the port to 465 and I try telnet again, this time
telnet smtp.sendgrid.net 465
I got no error. I test the endpoint again and everything works fine.
I hope this helps
Reference:
stackoverflow
nodemailersmtp

Error: connect ECONNREFUSED Nodemailer Ethereal

I have an error when trying to use the example from nodemailer.
I modified it a little bit but it has all of the same core. When I try to run it I get this error:
Error: connect ECONNREFUSED 13.49.22.0:587
at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1161:16) {
errno: -111,
code: 'ESOCKET',
syscall: 'connect',
address: '13.49.22.0',
port: 587,
command: 'CONN'
}
I have searched and I can't find any answers about this. I have heard that downgrading nodemailer's version to 4.7.0 fixes it but I have not tested this yet.
I also tested this connection to google, but it didn't work.
The function that is actually run is this:
async function nodeMailerMain() {
// 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().catch((err) => console.log(err))
// create reusable transporter object using the default SMTP transport
let transporter = await nodemailer.createTransport({
host: testAccount.smtp.host,
port: testAccount.smtp.port,
secure: testAccount.smtp.secure, // true for 465, false for other ports
auth: {
user: testAccount.user, // generated ethereal user
pass: testAccount.pass, // generated ethereal password
},
})//.catch((err) => console.log(err))
console.log(testAccount.smtp.host);
console.log("successfully created transporter");
let message = {
from: 'Sender Name <sender#example.com>',
to: 'Recipient <recipient#example.com>',
subject: 'Nodemailer is unicode friendly ✔',
text: 'Hello to myself!',
html: '<p><b>Hello</b> to myself!</p>'
};
// send mail with defined transport object
transporter.sendMail(message, (error, info) => {
if (error) {
return console.log(error);
}
console.log('Email sent: ' + info.response);
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...
});
}
It turns out that, since I was using a Gitpod workspace, the email functionality had been blocked to avoid spam-bots. See this issue on Github for more information: https://github.com/gitpod-io/gitpod/issues/8976

Nodemailer error while using gmail in firebase functions

I am using firebase cloud functions. I have the following setup configured. While that is working completely fine on my local machine, It's giving me an issue when run on the servers. I have tried gazillion work arounds on the internet but no luck. What is wrong with this?
'use strict'
const functions = require('firebase-functions');
var admin = require('firebase-admin');
const express = require('express');
const nodemailer = require('nodemailer');
const app = express()
var emailRecepient;
var userName;
const smtpTransport = nodemailer.createTransport({
service: "gmail",
host: 'smtp.gmail.com',
port: 587, // tried enabling and disabling these, but no luck
secure: false, // similar as above
auth: {
user: '<emailid>',
pass: '<password>'
},
tls: {
rejectUnauthorized: false
}
});
var mailOptions = {
from: 'test <hello#example.com>',
to: emailRecepient,
subject: 'Welcome to test',
text: 'welcome ' + userName + ". did you see the new things?"
};
function sendmail() {
smtpTransport.sendMail(mailOptions, function (error, info) {
if (error) {
console.log(error);
}
else {
console.log('Email sent: ' + info.response);
}
});
};
exports.sendEmails = functions.database.ref('/users/{userID}/credentials').onCreate((snap, context) => {
const userID = context.params.userID;
const vals = snap.val()
userName = vals.name;
emailRecepient = vals.email;
smtpTransport.sendMail(mailOptions, function (error, info) {
if (error) {
console.log("Error sending email ---- ",error);
}
else {
console.log('Email sent: ' + info.response);
}
});
return true;
});
The error I got on all cases is :
Error sending email 2 ---- { Error: Invalid login: 534-5.7.14 <https://accounts.google.com/signin/continue?sarp=1&scc=1&plt=AKgnsbsi
534-5.7.14 qRQLfD9YlFZDsPj7b8QQACro9c41PjhSVo0NZ4i5ZHNlyycFi_FyRp8VdZ_dH5ffWWAABQ
534-5.7.14 8rH2VcXkyZBFu00-YHJUQNOqL-IqxEsZqbFCwCgk4-bo1ZeDaKTdkEPhwMeIM2geChH8av
534-5.7.14 0suN293poXFBAk3TzqKMMI34zCvrZlDio-E6JVmTrxyQ-Vn9Ji26LaojCvdm9Bq_4anc4U
534-5.7.14 SpQrTnR57GNvB0vRX1BihDqKuKiXBJ5bfozV1D1euQq18PZK2m> Please log in via
534-5.7.14 your web browser and then try again.
534-5.7.14 Learn more at
534 5.7.14 https://support.google.com/mail/answer/78754 t2sm3669477iob.7 - gsmtp
at SMTPConnection._formatError (/user_code/node_modules/nodemailer-smtp-transport/node_modules/smtp-connection/lib/smtp-connection.js:528:15)
at SMTPConnection._actionAUTHComplete (/user_code/node_modules/nodemailer-smtp-transport/node_modules/smtp-connection/lib/smtp-connection.js:1231:30)
at SMTPConnection.<anonymous> (/user_code/node_modules/nodemailer-smtp-transport/node_modules/smtp-connection/lib/smtp-connection.js:319:22)
at SMTPConnection._processResponse (/user_code/node_modules/nodemailer-smtp-transport/node_modules/smtp-connection/lib/smtp-connection.js:669:16)
at SMTPConnection._onData (/user_code/node_modules/nodemailer-smtp-transport/node_modules/smtp-connection/lib/smtp-connection.js:493:10)
at emitOne (events.js:96:13)
at TLSSocket.emit (events.js:188:7)
at readableAddChunk (_stream_readable.js:176:18)
at TLSSocket.Readable.push (_stream_readable.js:134:10)
at TLSWrap.onread (net.js:559:20)
code: 'EAUTH',
response: '534-5.7.14 <https://accounts.google.com/signin/continue?sarp=1&scc=1&plt=AKgnsbsi\n534-5.7.14 qRQLfD9YlFZDsPj7b8QQACro9c41PjhSVo0NZ4i5ZHNlyycFi_FyRp8VdZ_dH5ffWWAABQ\n534-5.7.14 8rH2VcXkyZBFu00-YHJUQNOqL-IqxEsZqbFCwCgk4-bo1ZeDaKTdkEPhwMeIM2geChH8av\n534-5.7.14 0suN293poXFBAk3TzqKMMI34zCvrZlDio-E6JVmTrxyQ-Vn9Ji26LaojCvdm9Bq_4anc4U\n534-5.7.14 SpQrTnR57GNvB0vRX1BihDqKuKiXBJ5bfozV1D1euQq18PZK2m> Please log in via\n534-5.7.14 your web browser and then try again.\n534-5.7.14 Learn more at\n534 5.7.14 https://support.google.com/mail/answer/78754 t2sm3669477iob.7 - gsmtp',
responseCode: 534,
command: 'AUTH PLAIN' }
I have even turned of the allow secure apps in the google settings. But for some reason this doesn't seem to work. Any help is extremely appreciated.
As advised by Renaud, I tried firebase-samples/email-confirmation and I am having following error :
TypeError: snapshot.changed is not a function
at exports.sendEmailConfirmation.functions.database.ref.onWrite (/user_code/index.js:38:17)
at Object.<anonymous> (/user_code/node_modules/firebase-functions/lib/cloud-functions.js:112:27)
at next (native)
at /user_code/node_modules/firebase-functions/lib/cloud-functions.js:28:71
at __awaiter (/user_code/node_modules/firebase-functions/lib/cloud-functions.js:24:12)
at cloudFunction (/user_code/node_modules/firebase-functions/lib/cloud-functions.js:82:36)
at /var/tmp/worker/worker.js:758:24
at process._tickDomainCallback (internal/process/next_tick.js:135:7)
Cheers
When you execute an asynchronous operation in a background triggered Cloud Function, you must return a promise, in such a way the Cloud Function waits that this promise resolves in order to terminate.
This is very well explained in the official Firebase video series here: https://firebase.google.com/docs/functions/video-series/. In particular watch the three videos titled "Learn JavaScript Promises" (Parts 2 & 3 especially focus on background triggered Cloud Functions, but it really worth watching Part 1 before).
So you should modify your code as follows:
exports.sendEmails = functions.database.ref('/users/{userID}/credentials').onCreate((snap, context) => {
const userID = context.params.userID;
const vals = snap.val()
userName = vals.name;
emailRecepient = vals.email;
return smtpTransport.sendMail(mailOptions);
});
If you want to print to the console the result of the email sending, you can do as follows:
return smtpTransport.sendMail(mailOptions)
.then((info) => console.log('Email sent: ' + info.response))
.catch((error) => console.log("Error sending email ---- ", error));
});
Actually there is an official Cloud Functions sample that does exactly that, see https://github.com/firebase/functions-samples/blob/master/email-confirmation/functions/index.js
I see it was a long discussion, let me share the code snippets which worked out for me for others with similar issues so it will be easier to figure out.
1) function.ts (it's written in TypeScript)
import * as admin from 'firebase-admin';
import * as functions from 'firebase-functions';
import * as nodemailer from 'nodemailer';
admin.initializeApp();
// I'm taking all these constants as secrets injected dynamically (important when you make `git push`), but you can simply make it as a plaintext.
declare const MAIL_ACCOUNT: string; // Declare mail account secret.
declare const MAIL_HOST: string; // Declare mail account secret.
declare const MAIL_PASSWORD: string; // Declare mail password secret.
declare const MAIL_PORT: number; // Declare mail password secret.
const mailTransport = nodemailer.createTransport({
host: MAIL_HOST,
port: MAIL_PORT, // This must be a number, important! Don't make this as a string!!
auth: {
user: MAIL_ACCOUNT,
pass: MAIL_PASSWORD
}
});
exports.sendMail = functions.https.onRequest(() => {
const mailOptions = {
from: 'ME <SENDER#gmail.com>',
to: 'RECEIVER#gmail.com',
subject: `Information Request from ME`,
html: '<h1>Test</h1>'
};
mailTransport
.sendMail(mailOptions)
.then(() => {
return console.log('Mail sent'); // This log will be shown in Firebase Firebase Cloud Functions logs.
})
.catch(error => {
return console.log('Error: ', error); // This error will be shown in Firebase Cloud Functions logs.
});
});
This said, you should receive an e-mail from SENDER#gmail.com to RECEIVER#gmail.com, of course modify it for your own needs.
Note: I got the same issue with sending mails correctly on localhost, but on deployment it did not. Looks like the problem in my case was that I did not use port and host in createTransport, instead I had:
const mailTransport = nodemailer.createTransport({
service: 'gmail',
auth: {
user: MAIL_ACCOUNT,
pass: MAIL_PASSWORD
}
});
On top of this do not forget about enabling Less secure app access to ON. Also https://accounts.google.com/DisplayUnlockCaptcha might be helpful.
After checking that all the things listed above were done within my code, I solved the problem login in Google´s account (with the account I'm using with my proyect). I had to recognize the activity form another origin (google detected Firebase was trying to access to that account), and that was it.
After that I tryed to send another email from firebase cloud and it was working fine

Connection timeout error when sending mail from Zohomail using Nodemailer

Below is my Node app.js code. With these settings, I am receiving a connection timeout error. Any idea what I am missing here?
var nodemailer = require("nodemailer");
var transporter = nodemailer.createTransport({
host: 'smtp.zoho.com',
port: 465,
secure: true, // use SSL
auth: {
user: '<myemail#example.com>',
pass: '<myemailpassword>'
}
});
var mailOptions = {
from: "<fromemail#example.com>",
to: "<toemail#example.com>",
subject: "Hello",
generateTextFromHTML: true,
html: { path: './tmpl.html' }
};
transporter.sendMail(mailOptions, function(error, response) {
if (error) {
console.log(error);
} else {
console.log(response);
}
transporter.close();
});
Error shown
{ Error: Connection timeout
at SMTPConnection._formatError (/home/ubuntu/workspace/mailapp/node_modules/nodemailer/lib/smtp-connection/index.js:557:19)
at SMTPConnection._onError (/home/ubuntu/workspace/mailapp/node_modules/nodemailer/lib/smtp-connection/index.js:530:20)
at Timeout._connectionTimeout.setTimeout (/home/ubuntu/workspace/mailapp/node_modules/nodemailer/lib/smtp-connection/index.js:248:18)
at ontimeout (timers.js:380:14)
at tryOnTimeout (timers.js:244:5)
at Timer.listOnTimeout (timers.js:214:5) code: 'ETIMEDOUT', command: 'CONN' }
Can anyone please help me?
Some cloud providers disable ports like 465 and 587, try using port 2525 instead of 465.
Update
Since you're using Cloud9 for this I found out they have blocked all outbound smtp calls from their servers. If you need to send anyways you need to choose another cloud provider or use one of their recommended services.
https://community.c9.io/t/how-can-i-send-email-from-my-app/1262

ETIMEDOUT connect error using nodemailer in Nodejs Openshift application

I'm facing some problems using the nodemailer module in my node.js single gear non-scalable application in Openshift. As the documentation suggested, I initialized the transporter object and used the sendMail function. A simplified version of my code is
var transporter = nodemailer.createTransport({
service: 'Gmail',
auth: {
user: 'my.mail#gmail.com',
pass: 'mypassword'
}
});
var mail = {
from: 'my.mail#gmail.com',
to: 'test#mydomain.com',
subject: 'Test mail',
html: 'Test mail'
};
transporter.sendMail(mail, function(error, info) {
if(error){
console.log(error);
}else{
console.log(info);
}
});
This code works correctly when I run it on my local machine, but when I try to execute it on the server I got an ETIMEDOUT error, as if the application couln't connect to the smtp server.
{ [Error: connect ETIMEDOUT] code: 'ETIMEDOUT', errno: 'ETIMEDOUT', syscall: 'connect' }
I've tried to increase the timeout connection parameter, but I got the same results.
var transporter = nodemailer.createTransport({
service: 'Gmail',
auth: {
user: 'my.mail#gmail.com',
pass: 'mypassword'
},
connectionTimeout: 5 * 60 * 1000, // 5 min
});
Is there any firewall or default Openshift settings or enviroment variable I'm missing?
I've to run a few more tests, but I think I figured out what the problem was. The authentication via username and password is a not-secure authentication method for Gmail. As written in the Nodemailer documentation
Even though Gmail is the fastest way to get started with sending emails, it is by no means a preferable solution unless you are using OAuth2 authentication. Gmail expects the user to be an actual user not a robot so it runs a lot of heuristics for every login attempt and blocks anything that looks suspicious to defend the user from account hijacking attempts. For example you might run into trouble if your server is in another geographical location – everything works in your dev machine but messages are blocked in production.
I upgraded my authorization method using XOAuth2, as well explained in this guide and now the mails are correctly sent.
In my case the problem is with the port
I have changed port from 25 to 2525 and it worked.
try changing port
If you are trying to run this from the localhost.
Add the following line of code after the auth option
tls:{
rejectUnauthorized:false
}
It will work but you might consider upgrading to XOAuth2 as suggested by #matt.kiwi
const transporter = await nodemailer.createTransport(smtpTransport({
service: "Outlook365",
host: "smtp.office365.com",
port: "587",
tls: {
ciphers: "SSLv3",
rejectUnauthorized: false,
},
auth: {
user: '***',
pass: '***'
}
}));
It works for outlook

Resources