Merge pull request 'Email verification Backend' (#72) from Backend_Fix into main
Reviewed-on: #72
This commit was merged in pull request #72.
This commit is contained in:
Generated
+582
-41
File diff suppressed because it is too large
Load Diff
@@ -50,25 +50,25 @@
|
|||||||
"nodemailer": "^7.0.5",
|
"nodemailer": "^7.0.5",
|
||||||
"pg": "^8.16.3",
|
"pg": "^8.16.3",
|
||||||
"redis": "^5.8.1",
|
"redis": "^5.8.1",
|
||||||
|
"sharp": "^0.34.4",
|
||||||
"socket.io": "^4.8.1",
|
"socket.io": "^4.8.1",
|
||||||
|
"swagger-jsdoc": "^6.2.8",
|
||||||
|
"swagger-ui-express": "^5.0.1",
|
||||||
"tsconfig-paths": "^4.2.0",
|
"tsconfig-paths": "^4.2.0",
|
||||||
"typeorm": "^0.3.26",
|
"typeorm": "^0.3.26",
|
||||||
"uuid": "^11.1.0",
|
"uuid": "^11.1.0",
|
||||||
"winston": "^3.17.0",
|
"winston": "^3.17.0"
|
||||||
"swagger-jsdoc": "^6.2.8",
|
|
||||||
"swagger-ui-express": "^5.0.1"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/multer": "^2.0.0",
|
|
||||||
"@types/nodemailer": "^7.0.1",
|
|
||||||
"@types/uuid": "^10.0.0",
|
|
||||||
"@jest/globals": "^30.0.5",
|
"@jest/globals": "^30.0.5",
|
||||||
"@types/bcrypt": "^6.0.0",
|
"@types/bcrypt": "^6.0.0",
|
||||||
"@types/cookie-parser": "^1.4.9",
|
"@types/cookie-parser": "^1.4.9",
|
||||||
"@types/express": "^5.0.3",
|
"@types/express": "^5.0.3",
|
||||||
"@types/jest": "^30.0.0",
|
"@types/jest": "^30.0.0",
|
||||||
"@types/jsonwebtoken": "^9.0.10",
|
"@types/jsonwebtoken": "^9.0.10",
|
||||||
|
"@types/multer": "^2.0.0",
|
||||||
"@types/node": "^24.3.3",
|
"@types/node": "^24.3.3",
|
||||||
|
"@types/nodemailer": "^7.0.1",
|
||||||
"@types/pg": "^8.15.5",
|
"@types/pg": "^8.15.5",
|
||||||
"@types/redis": "^4.0.10",
|
"@types/redis": "^4.0.10",
|
||||||
"@types/socket.io": "^3.0.1",
|
"@types/socket.io": "^3.0.1",
|
||||||
@@ -76,6 +76,7 @@
|
|||||||
"@types/supertest": "^6.0.3",
|
"@types/supertest": "^6.0.3",
|
||||||
"@types/swagger-jsdoc": "^6.0.4",
|
"@types/swagger-jsdoc": "^6.0.4",
|
||||||
"@types/swagger-ui-express": "^4.1.8",
|
"@types/swagger-ui-express": "^4.1.8",
|
||||||
|
"@types/uuid": "^10.0.0",
|
||||||
"jest": "^30.0.5",
|
"jest": "^30.0.5",
|
||||||
"nodemon": "^3.1.10",
|
"nodemon": "^3.1.10",
|
||||||
"rimraf": "^5.0.10",
|
"rimraf": "^5.0.10",
|
||||||
|
|||||||
@@ -385,11 +385,12 @@ router.patch('/decks/:id', adminRequired, async (req: Request, res: Response) =>
|
|||||||
// Hard delete deck (admin only)
|
// Hard delete deck (admin only)
|
||||||
router.delete('/decks/:id/hard', adminRequired, async (req: Request, res: Response) => {
|
router.delete('/decks/:id/hard', adminRequired, async (req: Request, res: Response) => {
|
||||||
try {
|
try {
|
||||||
|
const adminUserId = (req as any).user.userId;
|
||||||
const deckId = req.params.id;
|
const deckId = req.params.id;
|
||||||
logRequest('Admin hard delete deck endpoint accessed', req, res, { deckId });
|
logRequest('Admin hard delete deck endpoint accessed', req, res, { deckId });
|
||||||
|
|
||||||
const result = await container.deleteDeckCommandHandler.execute({ id: deckId, soft: false });
|
const result = await container.deleteDeckCommandHandler.execute({ userid: adminUserId, authLevel: 1, id: deckId, soft: false });
|
||||||
|
|
||||||
logRequest('Admin deck hard delete successful', req, res, { deckId, success: result });
|
logRequest('Admin deck hard delete successful', req, res, { deckId, success: result });
|
||||||
res.json({ success: result });
|
res.json({ success: result });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import * as nodemailer from 'nodemailer';
|
import * as nodemailer from 'nodemailer';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
import sharp from 'sharp';
|
||||||
import { logError, logAuth, logStartup } from './Logger';
|
import { logError, logAuth, logStartup } from './Logger';
|
||||||
import { EmailTemplateHelper, LocalizedSubjects } from './EmailTemplateHelper';
|
import { EmailTemplateHelper, LocalizedSubjects } from './EmailTemplateHelper';
|
||||||
|
|
||||||
@@ -28,9 +29,14 @@ export class EmailService {
|
|||||||
private transporter!: nodemailer.Transporter;
|
private transporter!: nodemailer.Transporter;
|
||||||
private config: EmailConfig;
|
private config: EmailConfig;
|
||||||
private templatesPath: string;
|
private templatesPath: string;
|
||||||
|
private logoPath: string;
|
||||||
|
private resizedLogoBuffer?: Buffer;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.templatesPath = path.join(__dirname, '../../Templates');
|
this.templatesPath = path.join(__dirname, '../../Templates');
|
||||||
|
this.logoPath = path.join(__dirname, '../../../assets/Logo.png');
|
||||||
|
// Load logo asynchronously after initialization
|
||||||
|
this.loadLogoBase64().catch(err => console.error('[EmailService] Error loading logo:', err));
|
||||||
|
|
||||||
this.config = {
|
this.config = {
|
||||||
host: process.env.EMAIL_HOST || 'smtp.gmail.com',
|
host: process.env.EMAIL_HOST || 'smtp.gmail.com',
|
||||||
@@ -63,6 +69,32 @@ export class EmailService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load and resize logo for email attachments - 32x32 pixels
|
||||||
|
*/
|
||||||
|
private async loadLogoBase64(): Promise<void> {
|
||||||
|
try {
|
||||||
|
if (fs.existsSync(this.logoPath)) {
|
||||||
|
const logoBuffer = fs.readFileSync(this.logoPath);
|
||||||
|
|
||||||
|
// Resize to 60x60 pixels with high quality and centered
|
||||||
|
this.resizedLogoBuffer = await sharp(logoBuffer)
|
||||||
|
.resize(60, 60, {
|
||||||
|
fit: 'contain',
|
||||||
|
background: { r: 255, g: 255, b: 255, alpha: 1 },
|
||||||
|
position: 'center'
|
||||||
|
})
|
||||||
|
.png()
|
||||||
|
.toBuffer();
|
||||||
|
|
||||||
|
console.log(`[EmailService] ✅ Logo loaded and resized to 60x60`);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`[EmailService] ❌ Failed to load/resize logo:`, error);
|
||||||
|
logError('Failed to load logo for emails', error instanceof Error ? error : new Error(String(error)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send email with template
|
* Send email with template
|
||||||
* @param options - Email options including template and data
|
* @param options - Email options including template and data
|
||||||
@@ -73,19 +105,29 @@ export class EmailService {
|
|||||||
let textContent = options.text;
|
let textContent = options.text;
|
||||||
|
|
||||||
if (options.template) {
|
if (options.template) {
|
||||||
const templateResult = await this.loadTemplate(options.template, options.templateData || {});
|
const templateResult = await this.loadTemplate(options.template, options.templateData);
|
||||||
htmlContent = templateResult.html;
|
htmlContent = templateResult.html;
|
||||||
textContent = templateResult.text;
|
textContent = templateResult.text;
|
||||||
}
|
}
|
||||||
|
|
||||||
const mailOptions = {
|
const mailOptions: any = {
|
||||||
from: this.config.from,
|
from: this.config.from,
|
||||||
to: options.to,
|
to: options.to,
|
||||||
subject: options.subject,
|
subject: options.subject,
|
||||||
html: htmlContent,
|
html: htmlContent,
|
||||||
text: textContent
|
text: textContent,
|
||||||
|
attachments: []
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Add logo as CID attachment if available
|
||||||
|
if (this.resizedLogoBuffer) {
|
||||||
|
mailOptions.attachments.push({
|
||||||
|
filename: 'logo.png',
|
||||||
|
content: this.resizedLogoBuffer,
|
||||||
|
cid: 'logo@serpentrace' // Content-ID for referencing in HTML
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const result = await this.transporter.sendMail(mailOptions);
|
const result = await this.transporter.sendMail(mailOptions);
|
||||||
logAuth('Email sent successfully', undefined, {
|
logAuth('Email sent successfully', undefined, {
|
||||||
messageId: result.messageId,
|
messageId: result.messageId,
|
||||||
|
|||||||
@@ -22,18 +22,31 @@
|
|||||||
}
|
}
|
||||||
.header {
|
.header {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-bottom: 30px;
|
margin-bottom: 10px;
|
||||||
|
padding-bottom: 20px;
|
||||||
|
}
|
||||||
|
.header table {
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
.header img {
|
||||||
|
width: 60px;
|
||||||
|
height: 60px;
|
||||||
|
display: block;
|
||||||
}
|
}
|
||||||
.logo {
|
.logo {
|
||||||
font-size: 28px;
|
font-size: 28px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
color: #2c5aa0;
|
color: #2E7D32;
|
||||||
margin-bottom: 10px;
|
vertical-align: middle;
|
||||||
|
padding-left: 10px;
|
||||||
}
|
}
|
||||||
.subtitle {
|
.subtitle {
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
color: #666;
|
color: #666;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
|
text-align: center;
|
||||||
|
padding-bottom: 20px;
|
||||||
|
border-bottom: 2px solid #4CAF50;
|
||||||
}
|
}
|
||||||
.greeting {
|
.greeting {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
@@ -98,9 +111,14 @@
|
|||||||
<body>
|
<body>
|
||||||
<div class="email-container">
|
<div class="email-container">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<div class="logo">🐍 {{companyName}}</div>
|
<table cellpadding="0" cellspacing="0" border="0">
|
||||||
<div class="subtitle">Antwort auf Ihre {{contactTypeString}}</div>
|
<tr>
|
||||||
|
<td><img src="cid:logo@serpentrace" alt="Logo"/></td>
|
||||||
|
<td class="logo">🐍 SerpentRace</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="subtitle">Antwort auf Ihre {{contactTypeString}}</div>
|
||||||
|
|
||||||
<div class="greeting">
|
<div class="greeting">
|
||||||
Hallo {{contactName}},
|
Hallo {{contactName}},
|
||||||
|
|||||||
@@ -22,18 +22,31 @@
|
|||||||
}
|
}
|
||||||
.header {
|
.header {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-bottom: 30px;
|
margin-bottom: 10px;
|
||||||
|
padding-bottom: 20px;
|
||||||
|
}
|
||||||
|
.header table {
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
.header img {
|
||||||
|
width: 60px;
|
||||||
|
height: 60px;
|
||||||
|
display: block;
|
||||||
}
|
}
|
||||||
.logo {
|
.logo {
|
||||||
font-size: 28px;
|
font-size: 28px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
color: #2c5aa0;
|
color: #2E7D32;
|
||||||
margin-bottom: 10px;
|
vertical-align: middle;
|
||||||
|
padding-left: 10px;
|
||||||
}
|
}
|
||||||
.subtitle {
|
.subtitle {
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
color: #666;
|
color: #666;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
|
text-align: center;
|
||||||
|
padding-bottom: 20px;
|
||||||
|
border-bottom: 2px solid #4CAF50;
|
||||||
}
|
}
|
||||||
.greeting {
|
.greeting {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
@@ -98,9 +111,14 @@
|
|||||||
<body>
|
<body>
|
||||||
<div class="email-container">
|
<div class="email-container">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<div class="logo">🐍 {{companyName}}</div>
|
<table cellpadding="0" cellspacing="0" border="0">
|
||||||
<div class="subtitle">Válasz az Ön {{contactTypeString}} üzenetére</div>
|
<tr>
|
||||||
|
<td><img src="cid:logo@serpentrace" alt="Logo"/></td>
|
||||||
|
<td class="logo">🐍 SerpentRace</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="subtitle">Válasz az ön {{contactTypeString}}</div>
|
||||||
|
|
||||||
<div class="greeting">
|
<div class="greeting">
|
||||||
Kedves {{contactName}}!
|
Kedves {{contactName}}!
|
||||||
|
|||||||
@@ -22,18 +22,31 @@
|
|||||||
}
|
}
|
||||||
.header {
|
.header {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-bottom: 30px;
|
margin-bottom: 10px;
|
||||||
|
padding-bottom: 20px;
|
||||||
|
}
|
||||||
|
.header table {
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
.header img {
|
||||||
|
width: 60px;
|
||||||
|
height: 60px;
|
||||||
|
display: block;
|
||||||
}
|
}
|
||||||
.logo {
|
.logo {
|
||||||
font-size: 28px;
|
font-size: 28px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
color: #2c5aa0;
|
color: #2E7D32;
|
||||||
margin-bottom: 10px;
|
vertical-align: middle;
|
||||||
|
padding-left: 10px;
|
||||||
}
|
}
|
||||||
.subtitle {
|
.subtitle {
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
color: #666;
|
color: #666;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
|
text-align: center;
|
||||||
|
padding-bottom: 20px;
|
||||||
|
border-bottom: 2px solid #4CAF50;
|
||||||
}
|
}
|
||||||
.greeting {
|
.greeting {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
@@ -98,9 +111,14 @@
|
|||||||
<body>
|
<body>
|
||||||
<div class="email-container">
|
<div class="email-container">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<div class="logo">🐍 {{companyName}}</div>
|
<table cellpadding="0" cellspacing="0" border="0">
|
||||||
<div class="subtitle">Response to Your {{contactTypeString}}</div>
|
<tr>
|
||||||
|
<td><img src="cid:logo@serpentrace" alt="Logo"/></td>
|
||||||
|
<td class="logo">🐍 SerpentRace</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="subtitle">Response to Your {{contactTypeString}}</div>
|
||||||
|
|
||||||
<div class="greeting">
|
<div class="greeting">
|
||||||
Hello {{contactName}},
|
Hello {{contactName}},
|
||||||
|
|||||||
@@ -22,19 +22,31 @@
|
|||||||
}
|
}
|
||||||
.header {
|
.header {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-bottom: 30px;
|
margin-bottom: 10px;
|
||||||
border-bottom: 2px solid #FF9800;
|
|
||||||
padding-bottom: 20px;
|
padding-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
.header table {
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
.header img {
|
||||||
|
width: 60px;
|
||||||
|
height: 60px;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
.logo {
|
.logo {
|
||||||
font-size: 28px;
|
font-size: 28px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
color: #E65100;
|
color: #2E7D32;
|
||||||
margin-bottom: 10px;
|
vertical-align: middle;
|
||||||
|
padding-left: 10px;
|
||||||
}
|
}
|
||||||
.subtitle {
|
.subtitle {
|
||||||
color: #666;
|
color: #666;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
padding-bottom: 20px;
|
||||||
|
border-bottom: 2px solid #4CAF50;
|
||||||
}
|
}
|
||||||
.content {
|
.content {
|
||||||
margin-bottom: 30px;
|
margin-bottom: 30px;
|
||||||
@@ -123,9 +135,14 @@
|
|||||||
<body>
|
<body>
|
||||||
<div class="email-container">
|
<div class="email-container">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<div class="logo"><img src="../../assets/Logo.png" alt="{{ companyName }}" /> {{ companyName }}</div>
|
<table cellpadding="0" cellspacing="0" border="0">
|
||||||
<div class="subtitle">Passwort zurücksetzen</div>
|
<tr>
|
||||||
|
<td><img src="cid:logo@serpentrace" alt="Logo"/></td>
|
||||||
|
<td class="logo">SerpentRace</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="subtitle">Passwort zurücksetzen</div>
|
||||||
|
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<div class="greeting">
|
<div class="greeting">
|
||||||
|
|||||||
@@ -22,19 +22,31 @@
|
|||||||
}
|
}
|
||||||
.header {
|
.header {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-bottom: 30px;
|
margin-bottom: 10px;
|
||||||
border-bottom: 2px solid #FF9800;
|
|
||||||
padding-bottom: 20px;
|
padding-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
.header table {
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
.header img {
|
||||||
|
width: 60px;
|
||||||
|
height: 60px;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
.logo {
|
.logo {
|
||||||
font-size: 28px;
|
font-size: 28px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
color: #E65100;
|
color: #2E7D32;
|
||||||
margin-bottom: 10px;
|
vertical-align: middle;
|
||||||
|
padding-left: 10px;
|
||||||
}
|
}
|
||||||
.subtitle {
|
.subtitle {
|
||||||
color: #666;
|
color: #666;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
padding-bottom: 20px;
|
||||||
|
border-bottom: 2px solid #4CAF50;
|
||||||
}
|
}
|
||||||
.content {
|
.content {
|
||||||
margin-bottom: 30px;
|
margin-bottom: 30px;
|
||||||
@@ -123,9 +135,14 @@
|
|||||||
<body>
|
<body>
|
||||||
<div class="email-container">
|
<div class="email-container">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<div class="logo"><img src="../../assets/Logo.png" alt="{{ companyName }}" /> {{ companyName }}</div>
|
<table cellpadding="0" cellspacing="0" border="0">
|
||||||
<div class="subtitle">Jelszó visszaállítás kérése</div>
|
<tr>
|
||||||
|
<td><img src="cid:logo@serpentrace" alt="Logo"/></td>
|
||||||
|
<td class="logo">SerpentRace</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="subtitle">Jelszó visszaállítás kérése</div>
|
||||||
|
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<div class="greeting">
|
<div class="greeting">
|
||||||
|
|||||||
@@ -22,19 +22,31 @@
|
|||||||
}
|
}
|
||||||
.header {
|
.header {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-bottom: 30px;
|
margin-bottom: 10px;
|
||||||
border-bottom: 2px solid #FF9800;
|
|
||||||
padding-bottom: 20px;
|
padding-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
.header table {
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
.header img {
|
||||||
|
width: 60px;
|
||||||
|
height: 60px;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
.logo {
|
.logo {
|
||||||
font-size: 28px;
|
font-size: 28px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
color: #E65100;
|
color: #2E7D32;
|
||||||
margin-bottom: 10px;
|
vertical-align: middle;
|
||||||
|
padding-left: 10px;
|
||||||
}
|
}
|
||||||
.subtitle {
|
.subtitle {
|
||||||
color: #666;
|
color: #666;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
padding-bottom: 20px;
|
||||||
|
border-bottom: 2px solid #4CAF50;
|
||||||
}
|
}
|
||||||
.content {
|
.content {
|
||||||
margin-bottom: 30px;
|
margin-bottom: 30px;
|
||||||
@@ -123,9 +135,14 @@
|
|||||||
<body>
|
<body>
|
||||||
<div class="email-container">
|
<div class="email-container">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<div class="logo"><img src="../../assets/Logo.png" alt="{{ companyName }}" /> {{ companyName }}</div>
|
<table cellpadding="0" cellspacing="0" border="0">
|
||||||
<div class="subtitle">Password Reset Request</div>
|
<tr>
|
||||||
|
<td><img src="cid:logo@serpentrace" alt="Logo"/></td>
|
||||||
|
<td class="logo">SerpentRace</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="subtitle">Password Reset Request</div>
|
||||||
|
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<div class="greeting">
|
<div class="greeting">
|
||||||
|
|||||||
@@ -22,19 +22,31 @@
|
|||||||
}
|
}
|
||||||
.header {
|
.header {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-bottom: 30px;
|
margin-bottom: 10px;
|
||||||
border-bottom: 2px solid #4CAF50;
|
|
||||||
padding-bottom: 20px;
|
padding-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
.header table {
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
.header img {
|
||||||
|
width: 60px;
|
||||||
|
height: 60px;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
.logo {
|
.logo {
|
||||||
font-size: 28px;
|
font-size: 28px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
color: #2E7D32;
|
color: #2E7D32;
|
||||||
margin-bottom: 10px;
|
vertical-align: middle;
|
||||||
|
padding-left: 10px;
|
||||||
}
|
}
|
||||||
.subtitle {
|
.subtitle {
|
||||||
color: #666;
|
color: #666;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
padding-bottom: 20px;
|
||||||
|
border-bottom: 2px solid #4CAF50;
|
||||||
}
|
}
|
||||||
.content {
|
.content {
|
||||||
margin-bottom: 30px;
|
margin-bottom: 30px;
|
||||||
@@ -115,9 +127,14 @@
|
|||||||
<body>
|
<body>
|
||||||
<div class="email-container">
|
<div class="email-container">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<div class="logo"><img src="../../assets/Logo.png" alt="{{ companyName }}" /> {{ companyName }}</div>
|
<table cellpadding="0" cellspacing="0" border="0">
|
||||||
<div class="subtitle">Konto verifizieren</div>
|
<tr>
|
||||||
|
<td><img src="cid:logo@serpentrace" alt="Logo"/></td>
|
||||||
|
<td class="logo">SerpentRace</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="subtitle">Konto verifizieren</div>
|
||||||
|
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<div class="greeting">
|
<div class="greeting">
|
||||||
|
|||||||
@@ -22,19 +22,31 @@
|
|||||||
}
|
}
|
||||||
.header {
|
.header {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-bottom: 30px;
|
margin-bottom: 10px;
|
||||||
border-bottom: 2px solid #4CAF50;
|
|
||||||
padding-bottom: 20px;
|
padding-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
.header table {
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
.header img {
|
||||||
|
width: 60px;
|
||||||
|
height: 60px;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
.logo {
|
.logo {
|
||||||
font-size: 28px;
|
font-size: 28px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
color: #2E7D32;
|
color: #2E7D32;
|
||||||
margin-bottom: 10px;
|
vertical-align: middle;
|
||||||
|
padding-left: 10px;
|
||||||
}
|
}
|
||||||
.subtitle {
|
.subtitle {
|
||||||
color: #666;
|
color: #666;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
padding-bottom: 20px;
|
||||||
|
border-bottom: 2px solid #4CAF50;
|
||||||
}
|
}
|
||||||
.content {
|
.content {
|
||||||
margin-bottom: 30px;
|
margin-bottom: 30px;
|
||||||
@@ -115,9 +127,14 @@
|
|||||||
<body>
|
<body>
|
||||||
<div class="email-container">
|
<div class="email-container">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<div class="logo"><img src="../../assets/Logo.png" alt="{{ companyName }}" /> {{ companyName }}</div>
|
<table cellpadding="0" cellspacing="0" border="0">
|
||||||
<div class="subtitle">Fiók megerősítése</div>
|
<tr>
|
||||||
|
<td><img src="cid:logo@serpentrace" alt="Logo"/></td>
|
||||||
|
<td class="logo">SerpentRace</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="subtitle">Fiók megerősítése</div>
|
||||||
|
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<div class="greeting">
|
<div class="greeting">
|
||||||
|
|||||||
@@ -22,19 +22,32 @@
|
|||||||
}
|
}
|
||||||
.header {
|
.header {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-bottom: 30px;
|
margin-bottom: 10px;
|
||||||
border-bottom: 2px solid #4CAF50;
|
|
||||||
padding-bottom: 20px;
|
padding-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
.header table {
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
.header img {
|
||||||
|
width: 60px;
|
||||||
|
height: 60px;
|
||||||
|
display: block;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
.logo {
|
.logo {
|
||||||
font-size: 28px;
|
font-size: 28px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
color: #2E7D32;
|
color: #2E7D32;
|
||||||
margin-bottom: 10px;
|
vertical-align: middle;
|
||||||
|
padding-left: 10px;
|
||||||
}
|
}
|
||||||
.subtitle {
|
.subtitle {
|
||||||
color: #666;
|
color: #666;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
padding-bottom: 20px;
|
||||||
|
border-bottom: 2px solid #4CAF50;
|
||||||
}
|
}
|
||||||
.content {
|
.content {
|
||||||
margin-bottom: 30px;
|
margin-bottom: 30px;
|
||||||
@@ -115,9 +128,14 @@
|
|||||||
<body>
|
<body>
|
||||||
<div class="email-container">
|
<div class="email-container">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<div class="logo"><img src="../../assets/Logo.png" alt="{{ companyName }}" /> {{ companyName }}</div>
|
<table cellpadding="0" cellspacing="0" border="0">
|
||||||
<div class="subtitle">Account Verification</div>
|
<tr>
|
||||||
|
<td><img src="cid:logo@serpentrace" alt="Logo"/></td>
|
||||||
|
<td class="logo">SerpentRace</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="subtitle">Account Verification</div>
|
||||||
|
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<div class="greeting">
|
<div class="greeting">
|
||||||
|
|||||||
Reference in New Issue
Block a user