If you’re a good developer, you will be getting nightmares when it comes to interactions with third-party services. Be it calling third-party APIs or sending emails to a large number of people.
If the API is slow to respond, this might affect your system performance because of things outside your control. No one wants calls in the middle of the night because of third-party breakdown and the cussing that follows. So, we will introduce a new technique here to offload such independent pieces of work in separate lambda functions that run outside the scope of your app process and provide a layer of insulation to your app and also to your good night’s sleep.
Today's post will cover AWS SES & lambda function for sending an email to the customer using a small demo.
AWS SES is a managed service that is used to send and receive emails.
AWS Lambda is also a managed service that can spin up very temporary servers to compute small pieces of work.
Cloud-native features like AWS lambda are not unique to AWS, they are also present in other cloud providers. It’s called cloud functions in GCP for instance. For this post, we will focus on AWS Offering.
There are 5 main steps to be followed here,
1. Create an AWS accountWithout wasting much time let’s begin.
1. Create an AWS account here https://portal.aws.amazon.com/billing/signup#/start
2. Now go to IAM(Identity and Access Management)
a. Add new RoleIAM role creation is required to give access to your lambda function to perform the send email action and invoke the lambda function on your behalf.
Now Go to SES and register the email address/domain to send the email from your account.
Domain Setup in AWS SES
As soon as a new domain is added for verification DKIM record sets, TXT records, and MX(for receive) records are displayed, which must be added to the domain’s DNS settings.
Every email that you sent has the possibility of bounce or complaint. SES can send you detailed notifications about your bounces, complaints, and deliveries. You can configure this under the notifications tab.
You can send emails through Amazon SES by using applications or programming languages that use the SMTP protocol. We will, however, be using the AWS JS SDK in this example.
1. Go to AWS Lambda > Functions.
AWS Lambda is a serverless compute service that runs your code in response to events and automatically manages the underlying compute resources for you. You can use AWS Lambda to extend other AWS services with custom logic or create your own back-end services that operate at AWS scale, performance, and security.
2. Choose to create a function -> Choose Author from scratch.
The code you run on AWS Lambda is called a “Lambda function.” After you create your Lambda function it is always ready to run as soon as it is triggered, similar to a formula in a spreadsheet.
Each function includes your code as well as some associated configuration information, including the function name and resource requirements. Lambda functions are “stateless,” with no affinity to the underlying infrastructure, so that Lambda can rapidly launch as many copies of the function as needed to scale to the rate of incoming events.
3. Give the function a name. Choose runtime as Node.js 14x, select the permission as “Existing role”, and select the role that we have created earlier.
4. Once the lambda function is created. Go to Code, copy-paste the following code, and click deploy. Whenever changes are made to the code, always deploy the updated code.
AWS Lambda dashboard
const AWS = require('aws-sdk')
const sesConfig = {
apiVersion: '2010-12-01',
region: 'selected_region',
}
const ses = new AWS.SES(sesConfig)
exports.handler = async (event, context, callback) => {
const incomingMsg = JSON.parse(event.Records[0].body)
const params = {
Destination: {
ToAddresses: [incomingMsg.toEmail],
},
Message: {
Body: {
Html: {
Charset: 'UTF-8',
Data: incomingMsg.htmlContent,
},
Text: {
Charset: 'UTF-8',
Data: incomingMsg.textContent,
},
},
Subject: {
Charset: 'UTF-8',
Data:incomingMsg.subject,
},
},
ConfigurationSetName: configurationName,
Source: incomingMsg.source,
ReplyToAddresses: [
'email@domain.com',
],
}
await ses.sendEmail(params).promise().then((data) => {
console.log(data)
const response = {
"statusCode": 200,
"body": JSON.stringify(data),
"isBase64Encoded": false
};
callback(null, response);
}).catch((err) => {
console.error(err)
const response = {
"statusCode": 501,
"body": JSON.stringify(err),
"isBase64Encoded": false
};
callback(err,response);
});
}
In the send email function:
1. Destination
object contains ToAddresses
array which holds an array of email id to whom the email will be sent.
2. Message
object contains body and subject which is also an object that specifies email subject and body content of the email. You can send either HTML content or text content inside the message body.
3. Source
contains “from email address” which is used to send an email.
4. ReplyToAddresses
contains an array of email addresses to whom the email receiver can reply.
5. ConfigurationSetName
is a “set name” which is used to track email activity like transactional email/ promotional email.
You can set the configuration set name inside “SES -> Email Sending -> Configuration Sets -> setName(PromotionalEmail) -> Add destination as “CloudWatch” and select all the event types ->select Message tag for value source & set dimensions”
1. Go to AWS SQS > Create Queue.
Amazon SQS is a message queue service used to exchange messages through a polling model and can be used to decouple sending and receiving components.
2. Choose the queueing system bases on the requirement, for now, let’s choose the standard type.
3. Once the queue is created, go to lambda triggers and configure the lambda function that we have created.
4. Copy the URL of the queue for later use.
Once the SQS is set up, now we have to enqueue a message to the queue. We are going to use Node.js for this.
const emailToSend = {
email: “testUser@domain.com”,
htmlContent: ‘<p>Hello World</p>’,
textContent: ‘Hello World’
}
return new Promise((resolve, reject) => {
SQS.sendMessage({
MessageBody: JSON.stringify(emailToSend),
QueueUrl: “SQS_URL", //Copied from step 4
}, (err, data) => {
if (err) {
console.log(`Queueing email Failed`)
reject(err)
} else {
console.log(`Queueing email SQS message id ${data.MessageId}`)
resolve(data)
}
})}).catch((ignore) => console.log(ignore))
Once you run the above code, it will send the message to SQS, triggering the lambda function internally.
This post is just an example of de-coupling external services to lambda. This technique is applied to any long-running tasks or interactions with external services. You can also use DLQs for adding some fault tolerance in the lambda execution.
--
If you want to stay up to date with all the new content we publish on our blog, share your email and hit the subscribe button.
Also, feel free to browse through the other sections of the blog where you can find many other amazing articles on: Programming, IT, Outsourcing, and even Management.
Andres was born in Quito, Ecuador, where he was raised with an appreciation for cultural exchange. After graduating from Universidad San Francisco de Quito, he worked for a number of companies in the US, before earning his MBA from Fordham University in New York City. While a student, he noticed there was a shortage of good programmers in the United States and an abundance of talented programmers in South America. So he bet everything on South American talent and founded Jobsity -- an innovative company that helps US companies hire and retain Latin American programmers.