Skip to content

Commit a4a7165

Browse files
committed
update
- set mail limit - css adjustments
1 parent ca0d822 commit a4a7165

8 files changed

Lines changed: 1109 additions & 1151 deletions

File tree

netlify/functions/sendMail.ts

Lines changed: 43 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,20 @@ const corsHeaders = {
77
"Access-Control-Allow-Headers": "Content-Type",
88
};
99

10+
const ipStore: Record<string, { count: number; firstRequestTime: number }> = {};
11+
const MAX_EMAILS_PER_HOUR = 3;
12+
const ONE_HOUR_MS = 60 * 60 * 1000;
13+
14+
setInterval(() => {
15+
const now = Date.now();
16+
for (const ip in ipStore) {
17+
if (now - ipStore[ip].firstRequestTime > ONE_HOUR_MS) {
18+
delete ipStore[ip];
19+
}
20+
}
21+
}, 10 * 60 * 1000);
22+
1023
export const handler: Handler = async (event) => {
11-
// CORS Preflight
1224
if (event.httpMethod === "OPTIONS") {
1325
return {
1426
statusCode: 200,
@@ -17,7 +29,6 @@ export const handler: Handler = async (event) => {
1729
};
1830
}
1931

20-
// Only allow POST
2132
if (event.httpMethod !== "POST") {
2233
return {
2334
statusCode: 405,
@@ -26,29 +37,47 @@ export const handler: Handler = async (event) => {
2637
};
2738
}
2839

40+
const clientIP =
41+
event.headers["x-forwarded-for"] ||
42+
event.headers["client-ip"] ||
43+
event.headers["x-nf-client-connection-ip"] ||
44+
"unknown";
45+
46+
const now = Date.now();
47+
48+
if (!ipStore[clientIP]) {
49+
ipStore[clientIP] = { count: 1, firstRequestTime: now };
50+
} else {
51+
const elapsed = now - ipStore[clientIP].firstRequestTime;
52+
53+
if (elapsed < ONE_HOUR_MS) {
54+
if (ipStore[clientIP].count >= MAX_EMAILS_PER_HOUR) {
55+
return {
56+
statusCode: 429,
57+
headers: corsHeaders,
58+
body: JSON.stringify({
59+
error: "Rate limit exceeded: Max 3 emails per hour allowed.",
60+
}),
61+
};
62+
}
63+
ipStore[clientIP].count++;
64+
} else {
65+
ipStore[clientIP] = { count: 1, firstRequestTime: now };
66+
}
67+
}
68+
2969
try {
3070
const { firstname, lastname, email, subject, message } = JSON.parse(
3171
event.body || "{}"
3272
);
33-
console.log("Parsed body:", {
34-
firstname,
35-
lastname,
36-
email,
37-
subject,
38-
message,
39-
});
40-
// Optionally validate required fields
73+
4174
if (!firstname || !email || !message) {
4275
return {
4376
statusCode: 400,
4477
headers: corsHeaders,
4578
body: JSON.stringify({ error: "Missing required fields" }),
4679
};
4780
}
48-
// For debugging, log the event body and env vars
49-
console.log("Request body:", event.body);
50-
console.log("SMTP Host:", process.env.SMTP_HOST);
51-
console.log("SMTP User:", process.env.SMTP_USER);
5281

5382
const transporter = nodemailer.createTransport({
5483
host: process.env.SMTP_HOST,
@@ -65,7 +94,6 @@ export const handler: Handler = async (event) => {
6594
to: process.env.SMTP_TO,
6695
subject: subject,
6796
text: `${message} \n${email}`,
68-
// html: `<p>this is message in html</p>`,
6997
});
7098

7199
return {
@@ -74,7 +102,6 @@ export const handler: Handler = async (event) => {
74102
body: JSON.stringify({ message: "Email sent!" }),
75103
};
76104
} catch (error: any) {
77-
// Print error to log
78105
console.error("Error sending mail:", error);
79106
return {
80107
statusCode: 500,

0 commit comments

Comments
 (0)