How to fix sending emails with AWS SES and Lambda? - node.js

I'm setting up a simple NodeJS Lambda function on AWS to send emails.
The code below is working when I run it locally. I have received all the credentials from AWS, verified both sender and recipient emails and granted all permissions to SES for my Lamba
const aws = require("aws-sdk");
const config = require('../config')
aws.config.update({
accessKeyId: config.mailUser,
secretAccessKey: config.mailPassword,
region:'us-east-1'
});
const ses = new aws.SES({apiVersion: '2010-12-01'});
const sendEmail = async (mailOptions) => {
const {
from,
to,
subject,
html
} = mailOptions
console.log('foo')
ses.sendEmail({
Source: from,
Destination: {
ToAddresses: [to]
},
Message: {
Subject: {
Data: subject,
Charset: 'UTF-8'
},
Body: {
Html: {
Data: html,
Charset: 'UTF-8'
}
}
}
},
(err, data) => {
console.log('baz')
if (err) {
console.error(err);
} else {
console.log('Email sent:');
console.log(data);
}
});
};
console.log('bar')
module.exports = {
sendEmail
};
It seems that ses.sendEmail() never fires when the function is deployed - I get foo and bar in the CloudWatch logs but never baz. Again, everything is running smoothly if run locally.
What is it that I am missing?

https://www.reddit.com/r/aws/comments/bf2iss/lambda_function_not_able_to_send_email_using_ses/elb8vzr/
Here is a very good explanation - apparently you need to wrap your ses.sendMail call in a promise for it to work with AWS Lambda.
All credit goes to https://www.reddit.com/user/jsdfkljdsafdsu980p/ and https://www.reddit.com/user/Enoxice/

Related

AWS-SNS publish() method not sending any messages to phone number

I have used aws-sdk in node express to send the verification code to the phone number I referred this docs to implement it. here I get the response but do not get any messages on the phone.
const AWS = require("aws-sdk");
AWS.config.update({
region: "region",
accessKeyId: "ACCESS_KEY",
secretAccessKey: "SECRET_KEY",
});
router.post("/", async (req, res) => {
let phone_no = "+91876214****";
let random = Math.floor(100000 + Math.random() * 900000);
const YOUR_MESSAGE = `Your verification code is ${random}`;
let params = {
Message: YOUR_MESSAGE,
PhoneNumber: phone_no,
MessageAttributes: {
"AWS.SNS.SMS.SMSType": {
DataType: "String",
StringValue: "Transactional",
},
};
let publishTextPromise = new AWS.SNS({ apiVersion: "2010-03-31" })
.publish(params)
.promise();
publishTextPromise
.then(function (data) {
return res.json({ id: data.MessageId, otp: random });
})
.catch(function (err) {
return res.send(err.stack);
});
});
is anything I'm doing wrong, new to this aws-sns concept.
here i logged the publishTextPromise i get response as Promise { <pending> }
If you get Success result from api but message is not received. You need to check SNS logs.
On SNS console, you can see Text messaging (SMS) under Mobile section. If you don't enable status logging, firstly edit preferences on Delivery status logs section then on new page create an IAM Role (SNSSuccessFeedback) with Success sample rate 100%.
You can find error on cloudwatch.
Potential problem. You account is in the SMS sandbox in the region which you used.
If you see any message like ☝️, You can add your phone number on sandbox destination phone number.
Then sandbox will send you a verify code, when you put it on AWS console. Then you will be able to receive messages from SNS.

AWS Lambda email function does not always send

I have setup a custom flow with cognito to send MFA codes via email using lambda triggers. I have just noticed though that the function does not appear to always work and the emails are not always sent when requesting to login although the lambda metrics do not report any failures?
I have added some logs and checked in cloudwatch and the if statement to send the email is being hit and the sendEmail() method is executed but i dont see any email being sent in my inbox (i have checked the junk/spam)
My account is still in a sandbox mode but i havent hit my daily limits so quite confused what is going on.
Any ideas what is happening?
Here is a screenshot of the cloudwatch logs in an instance where no email was sent:
here is my lambda trigger below for sending emails:
const crypto = require("crypto");
var aws = require("aws-sdk");
var ses = new aws.SES({ region: "eu-west-2" });
exports.handler = async(event, context, callback) => {
var verificationCode = 0;
//Only called after SRP_A and PASSWORD_VERIFIER challenges.
if (event.request.session.length == 2) {
const n = crypto.randomInt(0, 100000);
verificationCode = n.toString().padStart(6, "0");
const minimumNumber = 0;
const maximumNumber = 100000;
verificationCode = Math.floor(Math.random() * maximumNumber) + minimumNumber;
console.log('send email');
console.log('verificationCode: '+ verificationCode);
console.log('verificationCode: '+ event.request.userAttributes.email);
const params = {
Destination: { ToAddresses: [event.request.userAttributes.email] },
Message: {
Body: {
Html: {
Charset: 'UTF-8',
Data: `<html><body><p>This is your secret login code:</p>
<h3>${verificationCode}</h3></body></html>`
},
Text: {
Charset: 'UTF-8',
Data: `Your secret login code: ${verificationCode}`
}
},
Subject: {
Charset: 'UTF-8',
Data: 'Your secret login code'
}
},
Source: 'my verified email address'
};
await ses.sendEmail(params).promise().then((res) => {
console.log(res);
});
}
else {
//if the user makes a mistake, we pick code from the previous session instead of sending new code
const previousChallenge = event.request.session.slice(-1)[0];
verificationCode = previousChallenge.challengeMetadata;
}
//add to privateChallengeParameters, so verify auth lambda can read this. this is not sent to client.
event.response.privateChallengeParameters = { "verificationCode": verificationCode };
//add it to session, so its available during the next invocation.
event.response.challengeMetadata = verificationCode;
return event;
};

Nodejs - AWS SNS publish is called, but message is not being sent

I'm trying to publish a SNS message to a single user.
The message is working when I manually press the "Publish Endpoint" button in the AWS console, but I'm trying to send it programmatically using the SNS nodejs SDK.
I have made sure to create a single IAM role giving full access permissions to SNS.
I have made sure to configure it:
const AWS = require("aws-sdk");
AWS.config.update({
region: process.env.AWS_REGION,
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY
});
I first create a platform endpoint using sns.createPlatformEndpoint(endPointParams) and it works fine so my IAM role is not an issue.
Using the result from that call, I use the data to create publishParams to make a call right after creating the endpoint:
let payload = {
user : "Hihih test",
shopping_list : "shopping_item"
};
let endPointParams = {
PlatformApplicationArn: process.env.REACT_APP_SNS_ARN,
Token: req.body.device_token
}
const createEndPoint = sns.createPlatformEndpoint(endPointParams).promise();
createEndPoint.then(data => {
console.log(data.EndpointArn);
console.log(JSON.stringify(payload));
let publishParams = {
Message: JSON.stringify(payload),
MessageStructure: 'json',
TargetArn: data.EndpointArn
};
sns.publish(publishParams, (err, result1) =>{
console.log("Success");
});
return;
}).then(result => {
res.status(200).send("Success sending invite to user.");
}).catch(err => {
console.log(err);
res.status(500).send("Something went wrong sending the invite.");
});
});
The console.log("Success"); inside sns.publish() is being fired, but on the client side, the app does not receive a message. I have also tried multiple times to manually call "Publish Message" in the console and it works fine.
So what could my issue be? I think it's something wrong with my code.
When using SNS with GCM you need to structure your JSON payload with the keys GCM and default or it will throw an err.
var payload = {
default: 'Hello World',
GCM: {
notification: {
title: 'Hello World',
body: 'Notification Body'
// other configs can be put here
}
}
};

AWS SES service issue in sending mail using lambda

I have a Basic AWS account in which we have deployed a lambda function. Also we have configured AWS SES service within the lambda function to send email (also our SES service is moved out of the sandbox & limit increased).
Approximately we are sending two emails per minute but we found that rarely we are getting mail, but most of the time we are not getting any email.
Also we tried deploying the application in two region but we found none to be successful.
Sample code
const AWS = require('aws-sdk');
//AWS Options
const options = {
region: 'us-east-1',
// accessKeyId not required because of server less app (SWS policy added in role)
// secretAccessKey not required because of server less app (SWS policy added in role)
}
const ses = new AWS.SES(options);
const sendEmail = (sender, receivers, subject, content) => {
console.log("Sending From", sender);
console.log("REceiver Email", receivers);
const promise = new Promise((resolve, reject) => {
ses.sendEmail({
Source: sender,
Destination: {
ToAddresses: receivers
},
Message: {
Subject: {
Data: subject
},
Body: {
Html: {
Data: content
}
}
}
}, (err, data) => {
if (err) {
console.log(err)
reject(err)
}
resolve(data)
});
});
return promise
};
I think there are a couple of things going on here:
JavaScript functions that return promises need to be async
your Lambda function may be timing out (the default is 3 seconds)

AWS - SNS - how to set sender on a per call basis?

How to set a sender while sending sms from AWS SNS service?
Checking the docs for SNS about sending SMS
https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/sns-examples-sending-sms.html#sending-sms-getattributes
And also here
https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/SNS.html#publish-property
With these docs combined I can send a sms but the sender remains unset. Why?
var AWS = require('aws-sdk');
AWS.config.update({ region: 'eu-west-1' });
var params = {
Message: 'TEXT_MESSAGE',
PhoneNumber: '+44123456780',
MessageAttributes: {
'SenderID': {
DataType: "String",
StringValue: "Company1",
}
}
};
var publishTextPromise = new AWS.SNS().publish(params).promise();
publishTextPromise.then(
function (data) {
console.log("MessageID is " + data.MessageId);
}).catch(
function (err) {
console.error(err, err.stack);
});
I can send a sms except I cannot see a way to set a sender.
How do I set a sender for each message?
I added following section under params for Node.js code and sender id works
MessageAttributes:{
"AWS.SNS.SMS.SenderID" : {
DataType: "String",
StringValue: "abc"
}
},
Note that senderId works for countries/regions as defined in AWS documentation:
https://docs.aws.amazon.com/sns/latest/dg/sns-supported-regions-countries.html#sms-support-note-1

Resources