Skip to content

Commit 1954939

Browse files
committed
Initial commit
0 parents  commit 1954939

File tree

6 files changed

+256
-0
lines changed

6 files changed

+256
-0
lines changed
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
name: deploy-web-s3
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
paths:
8+
- "index.ts"
9+
- ".github/workflows/deploy-lambda.yml"
10+
11+
env:
12+
LAMBDA_ARN: ${{ vars.LAMBDA_ARN }}
13+
14+
jobs:
15+
deploy:
16+
runs-on: ubuntu-latest
17+
environment: production
18+
permissions:
19+
id-token: write # This is required for requesting the JWT
20+
contents: read
21+
22+
steps:
23+
- name: Checkout repository
24+
uses: actions/checkout@v2
25+
26+
- name: Configure AWS credentials
27+
uses: aws-actions/configure-aws-credentials@v1
28+
with:
29+
role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
30+
aws-region: us-east-1
31+
32+
- name: Package repository and upload
33+
run: |
34+
pnpm install
35+
pnpm build
36+
zip -r function.zip dist node_modules
37+
38+
aws lambda update-function-code \
39+
--function-name $LAMBDA_ARN \
40+
--zip-file fileb://function.zip \
41+
--publish

.gitignore

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2+
3+
# dependencies
4+
/node_modules
5+
/.pnp
6+
.pnp.js
7+
8+
# testing
9+
/coverage
10+
11+
# next.js
12+
/.next/
13+
/out/
14+
15+
# production
16+
/build
17+
/dist
18+
*.zip
19+
*.tgz
20+
21+
# misc
22+
.DS_Store
23+
*.pem
24+
.vscode
25+
26+
# debug
27+
npm-debug.log*
28+
yarn-debug.log*
29+
yarn-error.log*
30+
.pnpm-debug.log*
31+
32+
# env files
33+
.env
34+
35+
# vercel
36+
.vercel
37+
38+
# typescript
39+
*.tsbuildinfo
40+
next-env.d.ts

index.ts

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import { APIGatewayProxyHandler } from "aws-lambda";
2+
import { treeifyError, z, ZodError } from "zod";
3+
import nodemailer from "nodemailer";
4+
5+
// Define schema
6+
const ContactEmailSchema = z.object({
7+
name: z.string(),
8+
email: z.email(),
9+
message: z.string(),
10+
});
11+
12+
// Email utility
13+
const generateMessageBody = ({
14+
name,
15+
email,
16+
message,
17+
}: {
18+
name: string;
19+
email: string;
20+
message: string;
21+
}) => `
22+
NAME: ${name}
23+
EMAIL: ${email}
24+
MESSAGE: "${message}"
25+
`;
26+
27+
const transport = nodemailer.createTransport({
28+
service: "gmail",
29+
auth: {
30+
user: process.env.NODEMAILER_EMAIL,
31+
pass: process.env.NODEMAILER_PASSWORD,
32+
},
33+
});
34+
35+
// Lambda entry point
36+
export const handler: APIGatewayProxyHandler = async (event) => {
37+
try {
38+
const body = JSON.parse(event.body || "{}");
39+
const parsed = ContactEmailSchema.parse(body);
40+
41+
await transport.sendMail({
42+
to: process.env.NODEMAILER_EMAIL,
43+
from: process.env.NODEMAILER_EMAIL,
44+
subject: `Contact form submission: ${parsed.name} (${parsed.email})`,
45+
text: generateMessageBody(parsed),
46+
});
47+
48+
return {
49+
statusCode: 201,
50+
body: JSON.stringify({ message: "Email sent" }),
51+
};
52+
} catch (error) {
53+
if (error instanceof ZodError) {
54+
return {
55+
statusCode: 400,
56+
body: JSON.stringify({
57+
error: "Invalid parameters provided.",
58+
details: treeifyError(error),
59+
}),
60+
};
61+
}
62+
63+
return {
64+
statusCode: 500,
65+
body: JSON.stringify({
66+
error: "Internal Server Error",
67+
details: error instanceof Error ? error.message : "Unknown",
68+
}),
69+
};
70+
}
71+
};

package.json

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{
2+
"name": "treehouse-technology-contact-email-lambda",
3+
"version": "1.0.0",
4+
"description": "",
5+
"main": "dist/index.js",
6+
"files": [
7+
"dist"
8+
],
9+
"scripts": {
10+
"build": "tsc"
11+
},
12+
"keywords": [],
13+
"author": "",
14+
"license": "ISC",
15+
"packageManager": "[email protected]+sha512.499434c9d8fdd1a2794ebf4552b3b25c0a633abcee5bb15e7b5de90f32f47b513aca98cd5cfd001c31f0db454bc3804edccd578501e4ca293a6816166bbd9f81",
16+
"dependencies": {
17+
"nodemailer": "^7.0.5",
18+
"zod": "^4.0.14"
19+
},
20+
"devDependencies": {
21+
"@types/aws-lambda": "^8.10.152",
22+
"@types/node": "^24.1.0",
23+
"@types/nodemailer": "^6.4.17",
24+
"typescript": "^5.8.3"
25+
},
26+
"bundleDependencies": [
27+
"nodemailer",
28+
"zod"
29+
]
30+
}

pnpm-lock.yaml

Lines changed: 64 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tsconfig.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"compilerOptions": {
3+
"target": "ES2020",
4+
"module": "CommonJS",
5+
"esModuleInterop": true,
6+
"strict": true,
7+
"outDir": "dist"
8+
},
9+
"include": ["index.ts"]
10+
}

0 commit comments

Comments
 (0)