
Serverless flood and drought alerts for Indian districts with AWS Lambda, SES and DynamoDB
How I built a district-level climate risk map for India with an email alert system on AWS: signed double opt-in links, a daily forecast check on EventBridge Scheduler, and the whole backend defined in one SAM template.
India's floods and droughts hit district by district, but most risk data is regional or buried in research datasets. A farmer in Madhubani or a volunteer in Jaisalmer has no easy way to see how risky their own district is, or to get a heads-up before it matters. So I built the India Climate Risk Tracker: a map that ranks the most affected districts, plus email alerts you can subscribe to for any district.
Live demo: [your link] | Source: [your GitHub link]
What it does
- An interactive map of India covering Assam, Bihar, Maharashtra and Rajasthan, showing the 10 most affected districts in each state.
- A flood or drought risk index from 2005 to 2025 for each district, with a year slider, a trend chart and the rivers behind the floods.
- Email alerts: pick a district, confirm your email, and get notified when risk is elevated.
- Youtube demo : https://www.youtube.com/watch?v=XNtllq2xs6g
Where the data comes from
A Python pipeline builds the index. Flood risk comes from Dartmouth Flood Observatory events matched to district boundaries, counting events, deaths and displaced people per district per year. Drought risk combines monsoon rainfall shortfall against the 2005 to 2020 average (60%) with chronic dryness (40%), using NASA POWER and Open-Meteo rainfall data. Districts are ranked by percentile, and the top 10 per state are kept. The result is a single JSON file that both the React app and the AWS backend read.
Architecture
The whole backend is serverless:
- React app (built with Vite) hosted as static files, with a "Notify me" box on every district card.
- Amazon API Gateway (HTTP API) provides the subscribe, confirm and unsubscribe endpoints, with CORS and request throttling.
- AWS Lambda (Node.js) runs four functions: subscribe, confirm, unsubscribe and the daily alert check.
- Amazon DynamoDB holds two tables: one for subscribers and one for the last alert sent per district.
- Amazon SES sends the confirmation and alert emails.
- Amazon EventBridge Scheduler triggers the alert check every morning at 07:00 IST.
- AWS SAM describes all of it in a single template, so the backend deploys as one unit.
Double opt-in without storing tokens
Nobody should be able to sign up someone else's email address, so every subscription starts as pending until the person clicks a confirmation link. Rather than storing a token for each link, the links are signed with a secret key using HMAC. The confirm function recomputes the signature and compares it in constant time, so a tampered link is rejected. Pending subscriptions get a DynamoDB time-to-live, so unconfirmed sign-ups delete themselves after 48 hours.
Email security scanners often open every link in a message. If simply opening a link could confirm or cancel a subscription, a scanner would do it on the person's behalf. So opening the link only shows a page with a button, and only pressing the button makes the change. Mail apps' one-click unsubscribe works the same way, so one handler serves both.
Flood alerts come from the forecast
A historical ranking tells you where risk is high, but an alert needs a signal about the future. Each morning the Lambda reads the 5-day rainfall forecast from Open-Meteo for every district that has subscribers. It uses the India Meteorological Department's daily rainfall categories as thresholds: 64.5 mm in a day counts as heavy rain, and 115.6 mm counts as very heavy.
If any of the next five days crosses a threshold, subscribers of that flood-prone district get an email saying where the district ranks and what the forecast shows. A cooldown stored in DynamoDB stops the same warning going out every day: the same level is not re-sent for 72 hours, but a jump from heavy to very heavy is sent straight away.
Being honest about drought
A rain forecast can't really predict a drought, so I didn't pretend it could. Drought-prone districts get one advisory per year at the start of the monsoon, when rainfall matters most. A better drought signal, such as IMD's rainfall deficit data, is on my list. Every email says it is an automated message and links to IMD and NDMA for official warnings.
Deploying with SAM
The backend deploys with the SAM command line tool: build, then a guided deploy. It asks for three things: the sender email address (verified in SES), the website address allowed to call the API, and a random secret for signing links. The template gives each function only the permissions it needs. For example, the alert check can only read the subscribers table, and email sending is limited to SES identities.
Things I ran into
- SES sandbox: new accounts can only send to verified addresses until you request production access, so verify your test recipients first.
- SMS in India: sending SMS through SNS requires DLT registration of sender IDs and message templates, so I started with email.
- Runtime deprecation: a template linter warned that Lambda's Node.js 20 runtime is deprecated, so I moved to Node.js 24.
- Don't reveal who is subscribed: the subscribe endpoint gives the same response whether or not an address is already registered.
- Testing without an AWS account: I mocked DynamoDB and SES in the tests, covering link signing, the alert rules, the cooldown and every handler.
What's next
More states, a better drought signal, SMS and WhatsApp alerts, and a history of past alerts. Because everything is pay-per-use, it should stay within the AWS free tier at small scale.
Thanks for reading. I'd love feedback, especially from anyone who works with district-level climate data.
Enjoyed reading this content? Let the author know!
Your likes, comments, shares, and saves help creators reach more builders.
Loading recommendations
Loading article