Skip to content

Commit

Permalink
send confirmation emails
Browse files Browse the repository at this point in the history
  • Loading branch information
davidteather committed Sep 8, 2023
1 parent 064083c commit 0ebbf6e
Show file tree
Hide file tree
Showing 8 changed files with 600 additions and 0 deletions.
28 changes: 28 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
lambda_function_payload.zip
node_modules

# Local .terraform directories
**/.terraform/*

# .tfstate files
*.tfstate
*.tfstate.*

# Crash log files
crash.log

# Ignore any .tfvars files, which could contain sensitive information
*.tfvars

# Ignore override files as they can contain sensitive information
override.tf
override.tf.json
*_override.tf
*_override.tf.json

# Ignore CLI configuration files
.terraformrc
terraform.rc

# Ignore all the .terraform directories
**/.terraform/*
19 changes: 19 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
LAMBDA_SRC_DIR = ./lambda
LAMBDA_ZIP = ./lambda_function_payload.zip
TERRAFORM_DIR = ./deployment

.PHONY: package-lambda deploy clean

all: package-lambda deploy

package-lambda:
@echo "Packaging Lambda function..."
cd $(LAMBDA_SRC_DIR) && zip -r ../lambda_function_payload.zip .

deploy: package-lambda
@echo "Deploying with Terraform..."
cd $(TERRAFORM_DIR) && terraform init && terraform apply -auto-approve

clean:
@echo "Cleaning up..."
rm -f $(LAMBDA_ZIP)
3 changes: 3 additions & 0 deletions TODO
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
* we should be handling bounce & complaint
* think this is required by AWS but I think we can manually handle these because we're super small scale
* we should still have bounce logic incase someone starts submitting tons of fake emails to us
24 changes: 24 additions & 0 deletions deployment/.terraform.lock.hcl

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

101 changes: 101 additions & 0 deletions deployment/lambda.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
variable "region" {
description = "The AWS region"
default = "us-east-1"
}

data "aws_region" "current" {}

provider "aws" {
region = var.region
}

resource "aws_iam_role" "lambda_ses_role" {
name = "LambdaSESSendEmailRole"

assume_role_policy = jsonencode({
Version = "2012-10-17",
Statement = [
{
Action = "sts:AssumeRole",
Principal = {
Service = "lambda.amazonaws.com"
},
Effect = "Allow",
Sid = ""
}
]
})
}

resource "aws_iam_role_policy_attachment" "ses_full_access" {
role = aws_iam_role.lambda_ses_role.name
policy_arn = "arn:aws:iam::aws:policy/AmazonSESFullAccess"
}

resource "aws_iam_role_policy_attachment" "lambda_cloudwatch_logs" {
role = aws_iam_role.lambda_ses_role.name
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
}

resource "aws_lambda_function" "ses_send_email" {
filename = "../lambda_function_payload.zip"
source_code_hash = filebase64sha256("../lambda_function_payload.zip")
function_name = "sesSendEmail"
role = aws_iam_role.lambda_ses_role.arn
handler = "index.handler"
runtime = "nodejs18.x"

environment {
variables = {
FROM_EMAIL = "[email protected]"
}
}
}

resource "aws_api_gateway_rest_api" "api" {
name = "SESSendEmailAPI"
description = "API to send email via SES"
}

resource "aws_api_gateway_resource" "email_resource" {
rest_api_id = aws_api_gateway_rest_api.api.id
parent_id = aws_api_gateway_rest_api.api.root_resource_id
path_part = "send-email"
}

resource "aws_api_gateway_method" "post_email" {
rest_api_id = aws_api_gateway_rest_api.api.id
resource_id = aws_api_gateway_resource.email_resource.id
http_method = "POST"
authorization = "NONE"
}

resource "aws_api_gateway_integration" "lambda" {
rest_api_id = aws_api_gateway_rest_api.api.id
resource_id = aws_api_gateway_resource.email_resource.id
http_method = aws_api_gateway_method.post_email.http_method

integration_http_method = "POST"
type = "AWS_PROXY"
uri = aws_lambda_function.ses_send_email.invoke_arn
}

resource "aws_lambda_permission" "api_gateway" {
statement_id = "AllowAPIGatewayInvoke"
action = "lambda:InvokeFunction"
function_name = aws_lambda_function.ses_send_email.function_name
principal = "apigateway.amazonaws.com"
}

resource "aws_api_gateway_deployment" "deployment" {
depends_on = [
aws_api_gateway_integration.lambda
]

rest_api_id = aws_api_gateway_rest_api.api.id
stage_name = "prod"
}

output "api_url" {
value = "https://${aws_api_gateway_rest_api.api.id}.execute-api.${data.aws_region.current.name}.amazonaws.com/prod/send-email"
}
67 changes: 67 additions & 0 deletions lambda/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
const AWS = require('aws-sdk');
const SES = new AWS.SES();

exports.handler = async (event) => {
const body = JSON.parse(event.body);

var to_email = "";
var first_name = "";
var last_name = "";

// iterate over body.data.fields and get the values for the fields we want
for (var i = 0; i < body.data.fields.length; i++) {

if (body.data.fields[i].key == "question_7R91WA") {
to_email = body.data.fields[i].value;
}

if (body.data.fields[i].key == "question_ja95yE") {
first_name = body.data.fields[i].value;
}

if (body.data.fields[i].key == "question_2Ex1eV") {
last_name = body.data.fields[i].value;
}
}

if (to_email == "" || first_name == "" || last_name == "") {
return {
statusCode: 500,
body: JSON.stringify({ error: "Missing required fields" }),
};
}


const subject = "Confirmation Of Application To MadHacks Fall 2023"
const body_text = "Hello " + first_name + ",\n\nThank you for applying to MadHacks Fall 2023! We will be reviewing your application and will get back to you soon.\n\nBest,\nMadHacks Team"

const params = {
Source: process.env.FROM_EMAIL,
Destination: {
ToAddresses: [to_email]
},
Message: {
Subject: {
Data: subject
},
Body: {
Text: {
Data: body_text
}
}
}
};

try {
await SES.sendEmail(params).promise();
return {
statusCode: 200,
body: JSON.stringify({ message: 'Email sent!' }),
};
} catch (error) {
return {
statusCode: 500,
body: JSON.stringify({ error: error.message }),
};
}
};
Loading

0 comments on commit 0ebbf6e

Please sign in to comment.