Sending mass email with AWS lambda, ses, sqs, sns - amazon-web-services

I'll be needing to send out approximately 200-300k emails a week for our weekly newsletter. This number is expected to increase over time which is why I thought of letting lambda handle the scaling for us.
There will be a UI for employees to trigger the sending of these emails. My initial thought was to add the list of email addresses to a SNS topic and have the lambda function subscribed to it to trigger the actual sending of the emails. I've read that this may lead to some unexpected behavior and isn't the best for tracking down bugs.
Our current limit is 90 emails per second. This combined with the max time to execute a lambda function being 5 minutes makes me wonder how to split this up. Do I need to batch send these to SNS so multiple lambda containers can be spun up evenly to do the work? I understand that lambda can scale up for events like adding files to S3 but how would I explicitly tell lambda to spin up multiple to handle all the emails that need to be sent? Is there a better design pattern for this?
My other thought was to add the emails into an SQS queue so the emails can be persisted incase of errors but would need to do some workaround to make that play nicely with lambda.
Update
I'm a few years late, but Lambda worked like a charm. Here is blog post detailing the architecture: https://read.iopipe.com/how-to-use-aws-lambda-to-send-high-volume-emails-at-scale-10efe65b2f32
And a follow up post on more specifics and lessons learned: https://read.iopipe.com/6-lessons-learned-sending-mass-emails-with-aws-lambda-3c5e56e19571

On the surface Lambda might appear to be a good solution, but it is not.
You will either need to develop your own software or port / migrate an existing solution. Managing email lists and sending emails is a task that will fit just fine on a normal EC2 instance (sized appropriately) along with RDS. The process of sending a single email is slow (for a lot of SMTP servers several seconds per email) so overlapping is critical. With Lambda you will pay for all those seconds that Lambda waits for the SMTP server to accept each email.
There are a lot of issues in sending bulk (large quantity of) emails. This is why third party services are becoming so popular. They provide a managed service that you just plug into your app and move on to the next task.
If you are going to use AWS to send emails, consider reading this Best Practices document:
Amazon Simple Email Service Email Sending Best Practices

One thing to keep in mind when implementing a Lambda-based solution is that each lambda is guaranteed to run at least once. Occasionally there will be a glitch and some of your users will receive duplicate emails. Here it is estimated that around 0.02% of all invocations result in multiple executions.

Related

AWS Lambda and SES - send personal email to multiple users [30 sec lambda limitation problem]

I'm using AWS lambda to build my web app (next.js) and I'm successfully sending email using AWS SES.
I set a CloudWatch event to run every day, that runs a lambda function that sends personal email to some of the users.
The problem is that lambda has running time limit of max 30sec so I can't use it to send emails to a lot of users.
What can I do to solve this issue?
After looking in the CloudWatch logs, I saw it took ~5sec to complete this lambda for ONE user.
So, I'm guessing it will not handle 100 users or more.
At first, it is strange that sending an email takes 5 seconds unless there is a heavy data preparation to format each email.
As for the lambda timeout, to have a scalable design, I recommend that you make lambda A --> SQS ---> lambda B.
Lambda A just writes messages to sqs (recipient's email, template name, whatever necessary info to format the email). Please note that you can write a batch of messages (10 messages) to SQS.. based on one of my previous implementations, it is easy to write 5000+ sqs messages in 30 sec. You can set a longer time up to 15 minutes if lambda is not behind an API.
lambda B will be triggered by SQS to format the email and send it to SES. You can set batch size and sqs config the best suits your design and quota. This way, you can always send emails regardless of the volume as long as quotas of AWS Account allows. Please note that you can also introduce a random delay to each message written to SQS to make sure the limit of SES is not violated (14/sec <== can be raised easily).
you may consider a better design too based on your app architecture :)

Storing values through AWS lambda

I am using AWS Lambda to check the health status and then send out an email. If the health is down I want it to send an email only once.
This Lambda function runs every 20minutes or so and I would like to prevent it from sending out multiple emails in interval if things have broken. Is there a way store environment variables or something in the AWS eco system so that it knows the state between each lambda function runs. (that way it doesnt send out an email and knows it has sent an email already).
I have looked into creating an alarm and sending out notifications but the email sent out through alarm wont do and I would like to have a custom email sent out, so I am using AWS SES through lambda. There is a cloud watch alarm that turns on when there is an error but I cant seem to fetch the state of alarm through the aws-sdk (its apparently not there).
I have written the function in NodeJS
Any suggestions ?
I've implemented something like this a little differently. I too do not care for getting an email for each error, since the errors I receive from my AWS Lambdas do not require immediate attention. I prefer to get them once an hour.
So I write all the errors I receive to an SQS queue. I configure the AWS Lambdas, which are throwing the errors, to send certain errors (configurable via environment variables) to certain SQS queues. Cloudwatch rules (running whenever), configured to pull from specific SQS queues in the Cloudwatch rule definition, then execute an AWS Lambda passing in the rule definition containing the SQS queue to pull from. The Lambda called by the CloudWatch rule handles reading from the SQS queue then emailing the results.
For your case you could modify that process to read all the errors from SQS, then filter that data down to the results you want to send. I use SQS because the "errors" I get don't need to be persisted.
I could see two quick ways to store something like a "last_email_sent" value. The first would be in DynamoDB. This is part of the AWS "serverless" environment that doesn't require you to do much more than interact with it. You didn't indicate your development environment but there are multiple development environments that are supported.
The second would be with the SSM Parameter Store. You can store any number of parameters there too.
There are likely other ways to do this too. Both of these are a bit of overkill but they would work to store what you need.
Alright, I found a better way that is simpler without dealing with other constraints. The NodeJS sdk is limited as it is. When the service is down create an alarm through the sdk and the next time the lambda gets triggered check if the alarm exists and send an email. That way if you want to do some notification through alarm it is possible too.
I think in my question I said this was not possible (last part), which I will retract.
Here is the link for the sdk reference: https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/CloudWatch.html

How to use AWS to send time-sensitive updates to my Android app

I'm basically just looking for a starting point here. I have an app which needs to include the ability to update certain data in real time. For instance, the user has the ability to specify that she wants X to happen exactly 24 hours from the current time. I want to implement a framework for updating this end-user and any other relevant end-users after 24 hours that the event has occurred. Can anyone just provide me with a high-level explanation of which AWS services to implement and how to implement them in order to achieve this sort of framework? I think it includes some combination of SNS and SQS, but I'm not sure if these are relevant since I don't need to send a message or notification, rather more of an update that some sort of data has changed. If it's relevant, I'm currently using RDS with a MySQL database and Cognito for establishing user identities. Thanks!
I think its most likely a combination of SNS, and an EC2 instance - plus your existing database (and optionally SQS).
SNS can take care of the 'push' notification to a mobile device, but you can't schedule things to happen in the future (except for a few minutes).
Off the top of my head I would say the database keeps a list of what needs to be pushed, when it needs to be pushed and to whom.
The Ec2 instance has a cron job of some sort that polls on some in interval, running queries against your database to find 'things that need to be pushed now'.
If something needs to get a pushed, the cron job uses SNS to do the push - that could either just be a message (hey, you need to get new data), or else if the data is small enough, you could send the data within the message itself.
If you wanted to add a bit of scaling capability, the cron job that finds items to be pushed could, instead of sending out the SNS notifications itself, add a message to an SQS queue (i.e. work to be done), and you could use as many Ec2 instances as you needed querying the SQS queue and then sending out the SNS notifications in a parallel fashion.

Amazon SNS : How to send a push to multiple recipients without using Topics?

Amazon SNS (Simple Notification Service) can break down my recipients to "Topics" which can then be used to send some messages to particular sub-segment of my app audience.
Let's say I have so many sub-segments of audiences that I can't use SNS Topics anymore (due to their limit).
Sending one by one is a heavy task.
Is it somehow possible to upload a list of pushIDs to SNS and then set the message and send the push message?
I don't think you can upload a list, bit you could ask AWS for limit increase or use multiple accounts.
You can request a topic limit increase here: https://aws.amazon.com/support/createCase
Unless you need some insane number of topics, this is probably your best bet.
You can use multiple micro ec2 instances to get over api limits. For this you have to divide workers into multiple instances. We implemented this a while ago and still using it without any problem.

AWS SNS Flexibility to Publish to Subset of Topic's Subscribers?

Here is the model I want to build:
Unlimited topics (I know the AWS limit is currently 3000)
Unlimited subscribers per topic (AWS SNS documentation does not state a limit)
Each subscriber will have a different schedule that they wish to receive SMS or email messages.
If I have a topic with 10 subscribers where 5 want morning messages and 5 want evening messages. The schedules can be changed and will be administered by a web app (utilizing the API) by an administrator so building one topic per schedule is not the ideal solution and the variations would chew up a lot of the 3000 topics.
SNS does not support the ability to publish to a subset of topic subscribers, other than when using its Android/iOS push notification capability, which is neither email nor http nor sms, and is so different than everything else SNS does, I'm not entirely sure why Amazon didn't market it as an entirely different product.
At this time, direct addressing is only supported for push notifications to iOS, Kindle, and Android endpoints
http://aws.amazon.com/sns/faqs/#Does_SNS_support_direct_addressing_for_SMS_or_Email
The documented limit for the number of subscribers to a single topic is 10,000. This appears to be a hard limit; however, the limit of 3,000 topics per account is apparently not a hard limit, since there is a documented process for requesting an increase to that limit.
There's a big gap between 3,000 topics of 10,000 subscribers each and 10 subscribers split among 2 or 3 topics, but it still doesn't seem like SNS is the right platform for what you're trying to do -- limits or no limits -- because every time a subscriber is added to a topic, they have to confirm their subscription to that topic... so if whatever your admin does to manipulate topic subscribership will still result in a confirmation message from "AWS Notifications" being sent to each subscriber from Amazon SNS requiring them to opt-in before subsequent messages can be delivered, and that's a process that would be have to be repeated if a subscriber wanted to change their delivery schedule (which means adding them to a new topic). You can't programmatically skip this step.
Within AWS, Simple Email Service seems like a more appropriate (and recipient-friendly, assuming your recipients are from the general public) platform based on what it seems like you're contemplating, with the logic of determining which recipients are associated with each message being determined by logic from your database... it doesn't have the same pricing structure, and it doesn't do SMS (though SMS through SNS seems pretty pricey at any rate), and unlike SNS, SES doesn't have a 256k limit per message.
That does put more of a burden on your application, since you'd have to send copies of the message to SES for each subscriber, but if outgoing bandwidth is an issue, an instance deployed inside EC2 could easily take care of replicating and transmitting the message to SES. With SES, you also get bounce and complaint notifications on your messages.
This is the approach I would take.
But then again, it's hard to tell exactly what you're asking.