Skip to content

Commit 9b52c0a

Browse files
author
Lasim
committed
feat(backend): add test email functionality and update support email address
1 parent fd410d1 commit 9b52c0a

File tree

8 files changed

+109
-4
lines changed

8 files changed

+109
-4
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ services/backend/tests/e2e/test-data/*.db
6868
._*.png
6969
._*.webp
7070
._*.jpg
71+
._*.pug
7172
._*.yml
7273
._*.yaml
7374
._*.css

services/backend/src/email/emailService.ts

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ export class EmailService {
311311
userName: options.userName,
312312
userEmail: options.userEmail,
313313
loginUrl: options.loginUrl,
314-
supportEmail: options.supportEmail || 'support@deploystack.com',
314+
supportEmail: options.supportEmail || 'hello@deploystack.io',
315315
},
316316
}, logger);
317317
}
@@ -334,7 +334,7 @@ export class EmailService {
334334
userName: options.userName,
335335
resetUrl: options.resetUrl,
336336
expirationTime: options.expirationTime,
337-
supportEmail: options.supportEmail || 'support@deploystack.com',
337+
supportEmail: options.supportEmail || 'support@deploystack.io',
338338
},
339339
}, logger);
340340
}
@@ -387,8 +387,41 @@ export class EmailService {
387387
changeTime: options.changeTime,
388388
ipAddress: options.ipAddress,
389389
userAgent: options.userAgent,
390-
loginUrl: options.loginUrl || 'https://app.deploystack.com/login',
391-
supportEmail: options.supportEmail || '[email protected]',
390+
loginUrl: options.loginUrl || 'https://cloud.deploystack.io/login',
391+
supportEmail: options.supportEmail || '[email protected]',
392+
},
393+
}, logger);
394+
}
395+
396+
/**
397+
* Send a test email to verify SMTP configuration (type-safe helper)
398+
*/
399+
static async sendTestEmail(options: {
400+
to: string;
401+
adminUser: string;
402+
appUrl?: string;
403+
supportEmail?: string;
404+
}, logger: FastifyBaseLogger): Promise<EmailSendResult> {
405+
const currentDateTime = new Date().toLocaleString('en-US', {
406+
timeZone: 'UTC',
407+
year: 'numeric',
408+
month: 'long',
409+
day: 'numeric',
410+
hour: '2-digit',
411+
minute: '2-digit',
412+
second: '2-digit',
413+
timeZoneName: 'short'
414+
});
415+
416+
return this.sendEmail({
417+
to: options.to,
418+
subject: '✅ DeployStack Email Test - Configuration Successful',
419+
template: 'test',
420+
variables: {
421+
testDateTime: currentDateTime,
422+
adminUser: options.adminUser,
423+
appUrl: options.appUrl || 'https://cloud.deploystack.io',
424+
supportEmail: options.supportEmail || '[email protected]',
392425
},
393426
}, logger);
394427
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
//- test.pug
2+
//- @description Test email template for verifying SMTP configuration
3+
//- @variables testDateTime, adminUser, appUrl, supportEmail
4+
extends layouts/base.pug
5+
6+
block content
7+
.test-header
8+
h1 ✅ Email Test Successful
9+
10+
.test-content
11+
p Hello!
12+
13+
p This is a test email from your DeployStack installation. If you're reading this, your SMTP configuration is working correctly.
14+
15+
.test-details
16+
h3 Test Details:
17+
ul
18+
li
19+
strong Test Time:
20+
| #{testDateTime}
21+
li
22+
strong Initiated by:
23+
| #{adminUser}
24+
li
25+
strong Application URL:
26+
a(href=appUrl)= appUrl
27+
28+
.test-actions
29+
p Your email system is ready to send:
30+
ul
31+
li Welcome emails for new users
32+
li Password reset notifications
33+
li System alerts and notifications
34+
li Team invitations
35+
36+
hr
37+
38+
.footer-note
39+
p
40+
em This email was sent as part of SMTP configuration testing. No action is required.
41+
42+
if supportEmail
43+
p
44+
| If you have questions, contact support at
45+
a(href=`mailto:${supportEmail}`)= supportEmail

services/backend/src/email/types.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,13 +130,21 @@ export interface PasswordChangedEmailVariables {
130130
supportEmail?: string;
131131
}
132132

133+
export interface TestEmailVariables {
134+
testDateTime: string;
135+
adminUser: string;
136+
appUrl: string;
137+
supportEmail?: string;
138+
}
139+
133140
// Template registry for type safety
134141
export interface TemplateVariableMap {
135142
welcome: WelcomeEmailVariables;
136143
'password-reset': PasswordResetEmailVariables;
137144
notification: NotificationEmailVariables;
138145
'email-verification': EmailVerificationVariables;
139146
'password-changed': PasswordChangedEmailVariables;
147+
test: TestEmailVariables;
140148
}
141149

142150
export type TemplateNames = keyof TemplateVariableMap;

services/backend/src/permissions/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ export const ROLE_DEFINITIONS = {
4141
'mcp.installations.create',
4242
'mcp.installations.edit',
4343
'mcp.installations.delete',
44+
'email.test',
4445
],
4546
global_user: [
4647
'profile.view',
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { type FastifyInstance } from 'fastify';
2+
import testRoute from './test';
3+
4+
export default async function adminEmailRoutes(fastify: FastifyInstance) {
5+
await fastify.register(testRoute);
6+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { type FastifyInstance } from 'fastify';
2+
import emailRoutes from './email';
3+
4+
export default async function adminRoutes(fastify: FastifyInstance) {
5+
await fastify.register(emailRoutes, { prefix: '/admin/email' });
6+
}

services/backend/src/routes/index.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ import healthRoute from './health'
2121
import mcpRoutes from './mcp'
2222
// Import OAuth2 routes
2323
import oauth2Routes from './oauth2'
24+
// Import admin routes
25+
import adminRoutes from './admin'
2426

2527
// Response schema for the root health check endpoint
2628
const healthCheckResponseSchema = z.object({
@@ -58,6 +60,9 @@ export const registerRoutes = (server: FastifyInstance): void => {
5860

5961
// Register OAuth2 routes
6062
await apiInstance.register(oauth2Routes);
63+
64+
// Register admin routes
65+
await apiInstance.register(adminRoutes);
6166
}, { prefix: '/api' });
6267

6368

0 commit comments

Comments
 (0)