emailService.tsā¢4.08 kB
import nodemailer from "nodemailer";
import { emailConfig } from "../config/email";
import { EmailRequest, EmailResponse } from "../types";
export class EmailService {
private transporter: nodemailer.Transporter;
constructor() {
this.transporter = nodemailer.createTransporter(emailConfig.smtp);
}
/**
* Send email notification
*/
async sendEmail(request: EmailRequest): Promise<EmailResponse> {
try {
// Validate email request
this.validateEmailRequest(request);
// Prepare email options
const mailOptions = {
from:
request.from ||
`${emailConfig.defaultFrom.name} <${emailConfig.defaultFrom.email}>`,
to: request.recipient,
subject: request.subject,
html: this.formatEmailBody(request.body),
text: request.body, // Plain text version
};
// Send email
const info = await this.transporter.sendMail(mailOptions);
return {
success: true,
messageId: info.messageId,
};
} catch (error) {
console.error("Email sending failed:", error);
return {
success: false,
error:
error instanceof Error ? error.message : "Unknown error occurred",
};
}
}
/**
* Send email with template
*/
async sendTemplatedEmail(
recipient: string,
subject: string,
body: string,
template: string = "default"
): Promise<EmailResponse> {
const templateData =
emailConfig.templates[template as keyof typeof emailConfig.templates];
if (!templateData) {
throw new Error(`Template '${template}' not found`);
}
const formattedBody = templateData.html.replace("{{body}}", body);
const finalSubject = subject || templateData.subject;
return this.sendEmail({
recipient,
subject: finalSubject,
body: formattedBody,
});
}
/**
* Test email configuration
*/
async testConnection(): Promise<boolean> {
try {
await this.transporter.verify();
return true;
} catch (error) {
console.error("Email connection test failed:", error);
return false;
}
}
/**
* Validate email request
*/
private validateEmailRequest(request: EmailRequest): void {
if (!request.recipient) {
throw new Error("Recipient email is required");
}
if (!request.subject) {
throw new Error("Email subject is required");
}
if (!request.body) {
throw new Error("Email body is required");
}
// Basic email validation
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(request.recipient)) {
throw new Error("Invalid recipient email format");
}
}
/**
* Format email body with basic HTML structure
*/
private formatEmailBody(body: string): string {
// If body already contains HTML tags, return as is
if (body.includes("<") && body.includes(">")) {
return body;
}
// Otherwise, wrap in basic HTML structure
return `
<div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto; padding: 20px;">
<div style="background-color: #f8f9fa; padding: 20px; border-radius: 8px; border-left: 4px solid #007bff;">
${body.replace(/\n/g, "<br>")}
</div>
<div style="margin-top: 20px; padding-top: 20px; border-top: 1px solid #dee2e6; color: #6c757d; font-size: 12px;">
<p>This email was sent from the MCP Server application.</p>
<p>Timestamp: ${new Date().toISOString()}</p>
</div>
</div>
`;
}
/**
* Get email configuration status
*/
getConfigStatus(): { configured: boolean; issues: string[] } {
const issues: string[] = [];
if (!emailConfig.smtp.host) {
issues.push("SMTP host not configured");
}
if (!emailConfig.smtp.auth.user) {
issues.push("SMTP user not configured");
}
if (!emailConfig.smtp.auth.pass) {
issues.push("SMTP password not configured");
}
return {
configured: issues.length === 0,
issues,
};
}
}