feat: Add conditional MAIL_HOST validation, lazy-load mailer, and update Gitea workflow to use vars for mail and Sentry environment variables.
Some checks failed
Build & Deploy KLZ Cables / 🔍 Prepare Environment (push) Successful in 14s
Build & Deploy KLZ Cables / 🧪 Quality Assurance (push) Successful in 1m44s
Build & Deploy KLZ Cables / 🏗️ Build App (push) Failing after 1m54s
Build & Deploy KLZ Cables / 🏗️ Build Gatekeeper (push) Successful in 31s
Build & Deploy KLZ Cables / 🚀 Deploy (push) Has been skipped
Build & Deploy KLZ Cables / ⚡ PageSpeed (push) Has been skipped
Build & Deploy KLZ Cables / 🔔 Notifications (push) Successful in 2s
Some checks failed
Build & Deploy KLZ Cables / 🔍 Prepare Environment (push) Successful in 14s
Build & Deploy KLZ Cables / 🧪 Quality Assurance (push) Successful in 1m44s
Build & Deploy KLZ Cables / 🏗️ Build App (push) Failing after 1m54s
Build & Deploy KLZ Cables / 🏗️ Build Gatekeeper (push) Successful in 31s
Build & Deploy KLZ Cables / 🚀 Deploy (push) Has been skipped
Build & Deploy KLZ Cables / ⚡ PageSpeed (push) Has been skipped
Build & Deploy KLZ Cables / 🔔 Notifications (push) Successful in 2s
This commit is contained in:
59
lib/mail/mailer.test.ts
Normal file
59
lib/mail/mailer.test.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { sendEmail } from './mailer';
|
||||
import { config } from '../config';
|
||||
|
||||
// Mock getServerAppServices to avoid full app initialization
|
||||
vi.mock('@/lib/services/create-services.server', () => ({
|
||||
getServerAppServices: () => ({
|
||||
logger: {
|
||||
child: () => ({
|
||||
info: vi.fn(),
|
||||
error: vi.fn(),
|
||||
warn: vi.fn(),
|
||||
}),
|
||||
},
|
||||
}),
|
||||
}));
|
||||
|
||||
// Mock config
|
||||
vi.mock('../config', () => ({
|
||||
config: {
|
||||
mail: {
|
||||
host: 'smtp.example.com',
|
||||
port: 587,
|
||||
user: 'user',
|
||||
pass: 'pass',
|
||||
from: 'from@example.com',
|
||||
recipients: ['to@example.com'],
|
||||
},
|
||||
},
|
||||
getConfig: vi.fn(),
|
||||
}));
|
||||
|
||||
describe('mailer', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('sendEmail', () => {
|
||||
it('should throw error if MAIL_HOST is missing', async () => {
|
||||
// Temporarily nullify host
|
||||
const originalHost = config.mail.host;
|
||||
(config.mail as any).host = '';
|
||||
|
||||
const result = await sendEmail({
|
||||
subject: 'Test',
|
||||
html: '<p>Test</p>',
|
||||
});
|
||||
|
||||
expect(result.success).toBe(false);
|
||||
expect((result.error as Error).message).toContain('MAIL_HOST is not configured');
|
||||
|
||||
// Restore host
|
||||
(config.mail as any).host = originalHost;
|
||||
});
|
||||
|
||||
// In a real environment, we'd mock nodemailer, but for now we focus on the validation logic
|
||||
// we added. Full SMTP integration tests are usually out of scope for unit tests.
|
||||
});
|
||||
});
|
||||
@@ -3,15 +3,27 @@ import { getServerAppServices } from '@/lib/services/create-services.server';
|
||||
import { config } from '../config';
|
||||
import { ReactElement } from 'react';
|
||||
|
||||
const transporter = nodemailer.createTransport({
|
||||
host: config.mail.host,
|
||||
port: config.mail.port,
|
||||
secure: config.mail.port === 465,
|
||||
auth: {
|
||||
user: config.mail.user,
|
||||
pass: config.mail.pass,
|
||||
},
|
||||
});
|
||||
let transporterInstance: nodemailer.Transporter | null = null;
|
||||
|
||||
function getTransporter() {
|
||||
if (transporterInstance) return transporterInstance;
|
||||
|
||||
if (!config.mail.host) {
|
||||
throw new Error('MAIL_HOST is not configured. Please check your environment variables.');
|
||||
}
|
||||
|
||||
transporterInstance = nodemailer.createTransport({
|
||||
host: config.mail.host,
|
||||
port: config.mail.port,
|
||||
secure: config.mail.port === 465,
|
||||
auth: {
|
||||
user: config.mail.user,
|
||||
pass: config.mail.pass,
|
||||
},
|
||||
});
|
||||
|
||||
return transporterInstance;
|
||||
}
|
||||
|
||||
interface SendEmailOptions {
|
||||
to?: string | string[];
|
||||
@@ -32,7 +44,7 @@ export async function sendEmail({ to, subject, html }: SendEmailOptions) {
|
||||
const logger = getServerAppServices().logger.child({ component: 'mailer' });
|
||||
|
||||
try {
|
||||
const info = await transporter.sendMail(mailOptions);
|
||||
const info = await getTransporter().sendMail(mailOptions);
|
||||
logger.info('Email sent successfully', { messageId: info.messageId, subject, recipients });
|
||||
return { success: true, messageId: info.messageId };
|
||||
} catch (error) {
|
||||
|
||||
Reference in New Issue
Block a user