Skip to content

Commit 51aea7f

Browse files
Added mail service
1 parent 6c74bce commit 51aea7f

File tree

6 files changed

+147
-2
lines changed

6 files changed

+147
-2
lines changed

backend/bun.lockb

764 Bytes
Binary file not shown.

backend/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,5 @@ const loadRoutes = async () => {
3333

3434

3535
loadRoutes().then(() => {
36-
app.listen(process.env.PORT || 3000, () => console.log(process.env.NODE_ENV == 'production' ? "Server started" : `Server started at http://localhost:${process.env.PORT || 3000}`))
36+
app.listen(process.env.PORT || 3000, () => console.log(process.env.NODE_ENV == 'production' ? "Server started" : `Server started at ${process.env.APP_URL}`))
3737
})

backend/package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,15 @@
1212
"express": "^5.1.0",
1313
"jsonwebtoken": "^9.0.2",
1414
"mongodb": "^6.15.0",
15+
"nodemailer": "^6.10.1",
1516
"zod": "^3.24.3"
1617
},
1718
"peerDependencies": {
1819
"typescript": "^5.0.0"
1920
},
2021
"devDependencies": {
2122
"@types/bun": "^1.2.10",
22-
"@types/jsonwebtoken": "^9.0.9"
23+
"@types/jsonwebtoken": "^9.0.9",
24+
"@types/nodemailer": "^6.4.17"
2325
}
2426
}

backend/src/routes/login.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { Router, type RequestHandler } from "express";
22
import { UserLogin } from "../validations/schemas";
33
import { users } from "../services/db";
44
import { generateAccessToken, generateRefreshToken } from "../utils/tokens";
5+
import { sendLoginMail } from "../services/mail";
56

67
const app = Router()
78

@@ -27,6 +28,7 @@ app.post('/login', LoginValidate, async (req, res) => {
2728
}
2829
const token = generateAccessToken(email, user.username)
2930
const rt = await generateRefreshToken(email, user.username)
31+
await sendLoginMail(email, user.username)
3032
res.status(200).send({status: 200, message: "User logged in", access_token: token, refresh_token: rt.token})
3133
} catch(_) {
3234
res.status(500).send({status: 500, message: "Unknown Error"})

backend/src/routes/register.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { RequestHandler, Router } from "express";
22
import { UserRegister } from "../validations/schemas";
33
import { users } from "../services/db";
44
import { generateAccessToken, generateRefreshToken } from "../utils/tokens";
5+
import { sendRegMail } from "../services/mail";
56

67
const app = Router()
78

@@ -27,6 +28,7 @@ app.post('/register', RegisterValidate, async (req, res) => {
2728
const rt = await generateRefreshToken(email, username)
2829
const pwd = await Bun.password.hash(password)
2930
await users.insertOne({email, username, password:pwd})
31+
await sendRegMail(email, username)
3032
res.status(201).send({status:201, message: "User Created", access_token: token, refresh_token: rt.token})
3133
} catch(_) {
3234
res.status(500).send({status:500, message: "Unknown Error"})

backend/src/services/mail.ts

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
import { createTransport } from "nodemailer";
2+
3+
const {sendMail} = createTransport({
4+
host: process.env.SMTP_HOST,
5+
port: parseInt(process.env.SMTP_PORT!),
6+
secure: parseInt(process.env.SMTP_PORT!) == 465,
7+
auth: {
8+
type: "oauth2",
9+
user: process.env.SMTP_USER,
10+
refreshToken: process.env.SMTP_REFRESH_TOKEN
11+
}
12+
})
13+
14+
const registrationEmailHtml = (username: string) => `
15+
<!DOCTYPE html>
16+
<html lang="en">
17+
<head>
18+
<meta charset="UTF-8">
19+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
20+
<style>
21+
body {
22+
font-family: Arial, sans-serif;
23+
line-height: 1.6;
24+
color: #333;
25+
}
26+
.container {
27+
max-width: 600px;
28+
margin: 0 auto;
29+
padding: 20px;
30+
background-color: #f7f7f7;
31+
border-radius: 8px;
32+
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
33+
}
34+
.header {
35+
text-align: center;
36+
padding-bottom: 20px;
37+
border-bottom: 1px solid #eaeaea;
38+
}
39+
.content {
40+
margin-top: 20px;
41+
}
42+
.footer {
43+
margin-top: 30px;
44+
text-align: center;
45+
font-size: 12px;
46+
color: #999;
47+
}
48+
</style>
49+
</head>
50+
<body>
51+
<div class="container">
52+
<div class="header">
53+
<h1>Thank You for Registering, ${username}!</h1>
54+
</div>
55+
<div class="content">
56+
<p>Dear ${username},</p>
57+
<p>We're thrilled to have you on board. Thank you for registering with us!</p>
58+
<p>We hope you enjoy your experience. If you have any questions, feel free to reach out.</p>
59+
</div>
60+
<div class="footer">
61+
<p>&copy; ${new Date().getFullYear()} Dev.Calender. All rights reserved.</p>
62+
</div>
63+
</div>
64+
</body>
65+
</html>
66+
`;
67+
68+
export const sendRegMail = async (email: string, username: string) => {
69+
await sendMail({
70+
from: process.env.SMTP_USER,
71+
to: email,
72+
subject: "Registration Confirmation",
73+
html: registrationEmailHtml(username)
74+
})
75+
}
76+
77+
const loginEmailHtml = (username: string) => `
78+
<!DOCTYPE html>
79+
<html lang="en">
80+
<head>
81+
<meta charset="UTF-8">
82+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
83+
<style>
84+
body {
85+
font-family: Arial, sans-serif;
86+
line-height: 1.6;
87+
color: #333;
88+
}
89+
.container {
90+
max-width: 600px;
91+
margin: 0 auto;
92+
padding: 20px;
93+
background-color: #f7f7f7;
94+
border-radius: 8px;
95+
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
96+
}
97+
.header {
98+
text-align: center;
99+
padding-bottom: 20px;
100+
border-bottom: 1px solid #eaeaea;
101+
}
102+
.content {
103+
margin-top: 20px;
104+
}
105+
.footer {
106+
margin-top: 30px;
107+
text-align: center;
108+
font-size: 12px;
109+
color: #999;
110+
}
111+
</style>
112+
</head>
113+
<body>
114+
<div class="container">
115+
<div class="header">
116+
<h1>New login from ${username}!</h1>
117+
</div>
118+
<div class="content">
119+
<p>Dear ${username},</p>
120+
<p>This is an automated email to let you know that we have a new login from your account.</p>
121+
<p>If you think someone else accessed your account, please contact support.</p>
122+
</div>
123+
<div class="footer">
124+
<p>&copy; ${new Date().getFullYear()} Dev.Calender. All rights reserved.</p>
125+
</div>
126+
</div>
127+
</body>
128+
</html>
129+
`;
130+
131+
export const sendLoginMail = async (email: string, username: string) => {
132+
await sendMail({
133+
from: process.env.SMTP_USER,
134+
to: email,
135+
subject: "New login from your account",
136+
html: loginEmailHtml(username)
137+
})
138+
}
139+
export default sendMail

0 commit comments

Comments
 (0)