AWS Lambda function that handles email verification for the CSYE6225 web application. Triggered by SNS, it validates a user's pending token and sends a verification email via Mailgun.
- The webapp publishes an SNS message containing
email,first_name, andtoken. - SNS invokes this Lambda function.
- Lambda retrieves the database password and Mailgun credentials from AWS Secrets Manager at cold-start.
- Lambda looks up the user in RDS and checks that the token matches and has not expired.
- If valid, it sends a verification email (HTML + plain-text) via the Mailgun API.
- The
verification_email_sentflag is set to prevent duplicate sends.
index.py # Lambda handler and all business logic
pyproject.toml # Python project and dependency definitions
uv.lock # Locked dependency versions
.python-version # Python version pin (3.14)
.github/
workflows/
ci.yaml # Build and deploy pipeline
Set by Terraform (tf-infra) on the Lambda function — never hardcoded. Sensitive credentials are not stored as plain environment variables; they are stored in AWS Secrets Manager and fetched at cold-start using the ARNs below.
| Variable | Description |
|---|---|
DOMAIN_NAME |
Application domain (e.g. dev.buildwithvaibhav.me) |
SENDER_EMAIL |
From address used in verification emails |
TOKEN_TTL_MINUTES |
Verification token lifetime in minutes (default 1) |
DATABASE_HOST |
RDS endpoint |
DATABASE_PORT |
RDS port (default 3306) |
DATABASE_USER |
RDS username |
DATABASE_NAME |
RDS database name |
DATABASE_SECRET_ARN |
ARN of the Secrets Manager secret containing the DB password |
MAILGUN_SECRET_ARN |
ARN of the Secrets Manager secret containing Mailgun credentials |
DATABASE_SECRET_ARN — JSON with keys: password, username, host, port, dbname
MAILGUN_SECRET_ARN — JSON with keys: api_key, domain
Both secrets are encrypted with a dedicated KMS Customer Managed Key (CMK) provisioned by Terraform.
The ci.yaml workflow builds and deploys the Lambda package on every commit to main.
| Event | Behaviour |
|---|---|
Push to main |
Build + deploy to dev, then demo |
Pull request to main |
Build only (no deploy) |
workflow_dispatch |
Build + deploy to the selected environment |
uv export→requirements.txtuv pip install --target build/— installspymysqlandrequestsintobuild/cp index.py build/— adds the handlerzip -r function.zip build/— produces the deployment artifact
boto3is not packaged — it is pre-installed in every Lambda Python 3.12 runtime.
git commit -m "fix: update token validation [deploy:dev]" # dev only
git commit -m "fix: update token validation [deploy:demo]" # demo only
git commit -m "fix: update token validation" # both (default)Configure under Settings → Secrets and variables → Actions in this repository (environment: CI).
| Secret | Description |
|---|---|
DEV_AWS_ACCESS_KEY_ID |
IAM access key for the dev account |
DEV_AWS_SECRET_ACCESS_KEY |
IAM secret key for the dev account |
DEV_AWS_REGION |
AWS region for dev (e.g. us-east-1) |
DEV_LAMBDA_FUNCTION_NAME |
Lambda function name in dev (e.g. webapp-dev-function) |
DEMO_AWS_ACCESS_KEY_ID |
IAM access key for the demo account |
DEMO_AWS_SECRET_ACCESS_KEY |
IAM secret key for the demo account |
DEMO_AWS_REGION |
AWS region for demo |
DEMO_LAMBDA_FUNCTION_NAME |
Lambda function name in demo |
Requires uv.
# Install dependencies
uv sync
# Verify import (does not invoke AWS or Mailgun)
uv run python -c "import index; print('import OK')"The Lambda function must be deployed and invoked via AWS for end-to-end testing — it requires live RDS, Secrets Manager, and Mailgun access.