How to send an email with nodemailer on AWS Lambda - node.js

I'm calling the following code ( with actual email addresses and passwords ) in my AWS Lambda function. Unfortunately, I'm unable to view the logs (my account currently doesn't have the permissions). Is there any specific permissions I have to set up to send an email from a lambda function? Or is there another/better way to send and email?
var transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: 'source#gmail.com',
pass: 'paswword'
}
});
var mailOptions = {
from: 'source#gmail.com',
to: 'destination#gmail.com',
subject: 'Sending Email using Node.js',
text: 'That was easy!'
};
transporter.sendMail(mailOptions, function(error, info){
if (error) {
console.log(error);
} else {
console.log('Email sent: ' + info.response);
}
});

Does it work locally? I'd start with that. Your method might be not working because https://www.google.com/settings/security/lesssecureapps feature is disabled.
Assuming you're using HTTP integration, if you cannot see logs, I'd create an array and instead of calling console.log, I'd append each log to that array. At the end of function, I would simply respond with 200 containing that logs.
You can also consider using https://aws.amazon.com/ses/. It's a cloud-based email sending service. It works great with AWS Lambda. In order to get it work, you need to add ses:SendEmail permissions and get through verification process.

Related

Trouble sending emails using Nodemailer with a Google App Password

I am creating a route on an API which features sending an email when a user signs up. I am using nodemailer and google app password to achieve this. It was working perfectly until February 3rd 2023 that was the last use of the password. However, I did not change any code the connection simply just stopped working.
This is how my code is formatted:
const transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: process.env.GOOGLE_EMAIL,
pass: process.env.GOOGLE_APP_PASSWORD
},
});
const mailOptions = {
from: process.env.GOOGLE_EMAIL,
to: "user#gmail.com",
subject: 'Test Email',
html: "<h1>Email is sent<h1>"
};
transporter.sendMail(mailOptions, function (error, info) {
if (error) {
console.log(error);
} else {
console.log('Email sent: ' + info.response);
}
});
I have also tried this format but it doesn't work either:
const transporter = nodemailer.createTransport({
host: "smtp.gmail.com",
port: 587, // or 465
secure: true,
auth: {
user: process.env.GOOGLE_EMAIL,
pass: process.env.GOOGLE_APP_PASSWORD
}
});
const mailOptions = {
from: process.env.GOOGLE_EMAIL,
to: "user#gmail.com",
subject: 'Test Email',
html: "<h1>Email is sent<h1>"
};
transporter.sendMail(mailOptions, function (error, info) {
if (error) {
console.log(error);
} else {
console.log('Email sent: ' + info.response);
}
});
In either case the error I receive after trying to send an email with either format is the following:
Error: Connection timeout
at SMTPConnection._formatError (/workspace/elana-backend/node_modules/nodemailer/lib/smtp-connection/index.js:787:19)
at SMTPConnection._onError (/workspace/elana-backend/node_modules/nodemailer/lib/smtp-connection/index.js:773:20)
at Timeout.<anonymous> (/workspace/elana-backend/node_modules/nodemailer/lib/smtp-connection/index.js:232:22)
at listOnTimeout (node:internal/timers:559:17)
at processTimers (node:internal/timers:502:7) {
code: 'ETIMEDOUT',
command: 'CONN'
}
The first block of code was working perfectly fine up until recently. I thought a possible password change may have revoked the app password because I noticed that in google app password documentation. Therefore, I also created a new app password but it still appeared with the same issue.
Edit -
Are you using an App Password to make these requests? This password is used to connect applications to your Google account and WILL NOT allow you to login/authenticate with your Google account
Have you tried using a service account with domain-wide delegation to send the email?
I use a similar piece of code to send emails (as users in our Google Workspace) when a Slack message is posted in a channel, however I struggled to have success authenticating using basic authentication like you are above. Instead I took a suggestion from #Linda Lawton - DalmTo in this question. Below I am using OAuth2.0 to impersonate a service account that is authorized through domain-wide delegation to send emails as users in the workspace. Sample code:
const transport = nodemailer.createTransport({
service: 'Gmail',
auth: {
type: 'OAuth2',
user: process.env.GOOGLE_EMAIL,
//Derived from Service Account
serviceClient: privatekey.client_id,
privateKey: privatekey.private_key
}
})
const mail_options = {
from: process.env.GOOGLE_EMAIL,
to: 'test#gmail.com',
subject: 'Test Mail',
html: '<h1> Test Email </h1>',
}
transport.sendMail(mail_options, function(error, result){
if(error){
console.log('Error: ' + error);
}else{
console.log('Result: ' + result);
}
transport.close();
})
Google has some confusing, but well written documentation on using domain-wide delegation in your workspace here. If you are not familiar with Google Cloud services there might be some other resources to catch up on with as well
You might also need to add the transport.close() method in the body of the callback in your .sendMail() method
References
OAuth2.0 with Service Accounts
Domain-Wide Delegation with Service Account
Domain-Wide Delegation
Service Accounts

Send mail to multiple recipients using nodemailer

how to send mail to multiple recipients which are stored in database(mongodb) using nodemailer?
Currently Im sending to single recipient. But im not able to figure out how to send mail to multiple people whose mail ids are stored in mongodb.
If someone knows the answer, please respond.
Thank you in advance :)
Use mongodb distinct to get array for all the email_address you want to send the email, and pass that array to nodemailer.
const nodemailer = require('nodemailer');
// create reusable transporter object using the default SMTP transport
let transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: 'gmail.user#gmail.com',
pass: 'yourpass'
}
});
let email_arr = db.users.distinct( "email", { /* Any condition you want to put*/ } )
let mailOptions = {
from: "test#example.com", // sender address
subject: "Hello ✔", // Subject line
text: "Hello This is an auto generated Email for testing from node please ignore it", // plaintext body
to: email_arr
}
// send mail with defined transport object
transporter.sendMail(mailOptions, (error, info) {
if (error) {
return console.log(error);
}
console.log('Message %s sent: %s', info.messageId, info.response);
});

nodemailer fails on Heroku

I trying to send an email using node.js and the module node-mailer on heroku, but it is failing. I show you the code I have (I think simple), and after I´ll explain better.
var nodemailer = require('nodemailer');
var transporter = nodemailer.createTransport({
service: 'Gmail',
auth: {
user: 'example#gmail.com',
pass: 'pass'
}
});
exports.sendAnEmail = function(receivers, tittle, user, message, jsonBack, callBack)
{
var mailOptions =
{
from: "User example#gmail.com", // sender address
to: receivers,
subject: tittle, // Subject line
html: message // html body
};
transporter.sendMail(mailOptions, function(err, response)
{
if(err)
console.log("email.js->sendAnEmail-> error: " + err)
else
console.log("email.js->sendAnEmail-> NO error")
if(callBack && typeof(callBack)=="function")
callBack();
});
}
If I execute this code (or rather, the code that invoke that) on local it works fine, but if I execute (on the git console) heroku run cron (it will be a schedule task on heroku), the console spits this: "email.js->sendAnEmail-> error: Error: Invalid login".
I tryed to access my account coying and pasting the user and the pass and it let me in.
Do I need to do something else using heroku (or using schedule) to make it works??
Thank you.

Nodejs send mails

Hi I've sent some mails using express mailer. My problem is, when I need to send mails it's asking for my credentials and using that email to send. However, I want to send emails from a no-reply email but this would mean sending emails from an account thats not set up.
I know in other application servers you can pretty much send emails from any email address, even one which is not your own. I'm wondering how I can do this with nodejs or expressjs.
Edit:
var nodemailer = require('nodemailer');
var transporter = nodemailer.createTransport({
service: 'Gmail',
auth: {
user: 'yang#example.com',
pass: '****'
}
});
var mailOptions = {
from: 'noreply#send.com',
to: 'yang#receive.com',
subject: 'Hello ✔',
text: 'Hello world ✔',
html: '<b>Hello world ✔</b>'
};
transporter.sendMail(mailOptions, function(error, info){
if(error){
console.log(error);
}else{
console.log('Message sent: ' + info.response);
}
});
I've tried this but it's still sending from yang#example.com which is the server I logged in with
Google SMTP servers automatically set your sending address to the one you logged in with.
If you want to send e-mail with an address which isn't your own, you should use a different SMTP server or set up your own one (Haraka, smtp-server, etc.)
You should be able to set the "reply-to" or "from" to whatever you need to. It's independent of which email account you use to send the email. Like an address on a postage mail envelope.
Nodemailer is a bit more robust in my personal experience: https://www.npmjs.org/package/nodemailer
And for higher volume setting up a service like Amazon SES as your transport.

Nodemailer with Gmail service not working on heroku

I've got a basic email setup done for sending an email using Nodemailer with AngularJS and NodeJS and I've got the project deployed on heroku.
The emailing seems to be working just fine when I am running the app on heroku, but when I get it deployed to Heroku no emails are sent.
For authentication, I am using a Gmail address and I also have a bcc to another Gmail address. So from and bcc addresses are two different Gmail addresses. The from address is the same as the address used for authentication.
Could somebody help me with resolving this issue?
Edit: Adding code
var nodemailer = require('nodemailer');
var transporter = nodemailer.createTransport({
service: 'Gmail',
auth: {
user: 'foobar#gmail.com',
pass: 'foobar'
}
});
router.post('/send',function(req,res){
var mailOptions = {
from: 'Foo Bar ✔ <foobar#gmail.com>',
to: req.body.email,
subject: "Hello " + req.body.email,
text: 'Hello ' + req.body.email + '✔',
html: "<p>Hello " + req.body.email + " </p>",
bcc: "fred#gmail.com"
};
transporter.sendMail(mailOptions, function(error, info){
if(error){
console.log(error);
}else{
console.log('Message sent: ' + info.response);
res.send(200);
}
});
});
I believe this is an issue with google account security.
Google blocked your sign-in to use the mailing features due to an unknown device (location).
A few step to verify this:
Start your server locally and sends the email.
Check your account alerts for unknown sign-in.
This can be temporally resolved by:
https://accounts.google.com/DisplayUnlockCaptcha
A more permanent resolution would be to change your password to a stronger level:
upper case letter + lower case letter + special symbols + numbers
Instead of using direct gmail credentials like this
auth: {
user: 'foobar#gmail.com',
pass: 'foobar'
}
Use OAuth2
auth: {
type: 'OAuth2',
user: 'user#example.com',
accessToken: 'ya29.Xx_XX0xxxxx-xX0X0XxXXxXxXXXxX0x'
}
Google blocks the heroku IPs (unsafe), if we are using direct credentials like you mentioned above. You can refer this Medium article here
5 years later, I still struggled this problem (all answers found on SO failed in my case). Here is what I did, for now everything works smoothly:
Install SendGrid addon to your Heroku app (Free plan gives you 12k messages a month)
Go to SendGrid panel
Go to Marketing -> Senders to add your sender bot, configure it like this:
From = any_address#heroku.com
Reply = your_gmail#gmail.com
Generate API KEY here
Configure NodeMailer like so:
const nodemailer = require('nodemailer'),
sgTransport = require('nodemailer-sendgrid-transport');
const mailTransporter = nodemailer.createTransport(sgTransport({
auth: {
api_key: process.env.ADMIN_EMAIL_API_KEY // your api key here, better hide it in env vars
}
}))
To send an email now, you have to add your gmail in 'Reply To' field, like so:
mailTransporter.sendMail({
from: `"Admin" <any_address#heroku.com>`,
to: 'receiver#hotmail.com',
replyTo: 'your_gmail#gmail.com',
subject: 'Something',
html: `Boom !`
});
I think that's all, in case I forgot something, please add a comment below
Try updating nodemailer package (using "npm update nodemailer" command)
var transporter = nodemailer.createTransport({
host: 'smtp.gmail.com',
port: 465,
secure: true,
auth: {
user: 'youremai#gmail.com', // Your email id
pass: 'pwd123' // Your password
},
tls: {
// do not fail on invalid certs
rejectUnauthorized: false
}
});
router.post('/send',function(req,res){
var mailOptions = {
from: 'Foo Bar ✔ <foobar#gmail.com>',
to: req.body.email,
subject: "Hello " + req.body.email,
text: 'Hello ' + req.body.email + '✔',
html: "<p>Hello " + req.body.email + " </p>",
bcc: "fred#gmail.com"
};
transporter.sendMail(mailOptions, function(error, info){
if(error){
console.log(error);
}else{
console.log('Message sent: ' + info.response);
res.send(200);
}
});
});
I know I'm too late but hopefully someone will find it helpful.
At the time of writing, Less Secure Apps is no longer supported by google.
And you can't use your google account password.
You're gonna have to generate a new app password.
Follow this link
In the "Select App" dropdown, select Other and give the app a name (could be anything)
Copy the password and replace it with your original password
It works on Local machine and Heroku.
const client = nodemailer.createTransport({
service: "Gmail",
auth: {
user: "username#gmail.com",
pass: "Google-App-Password-Without-Spaces"
}
});
client.sendMail(
{
from: "sender",
to: "recipient",
subject: "Sending it from Heroku",
text: "Hey, I'm being sent from the cloud"
}
)
App passwords only work if 2-step verification is turned on. You can do so here
Also if your app password is in your .env file you have to add it to the config vars in the settings tab of your app at heroku.

Resources