/**
* Mailgun Email Service
* This service handles email sending via Mailgun API
*/
import { getMailgunConfig, type MailgunConfig } from './mailgun.config';
import { getAppConfig } from '../config/unified.config';
interface EmailTemplate {
subject: string;
html: string;
text?: string;
}
export class MailgunService {
private config: MailgunConfig;
constructor() {
this.config = getMailgunConfig();
// Log configuration status on startup
const status = this.getConfigurationStatus();
if (status.mode === 'development') {
console.warn(
'📧 Mailgun Service: Running in development mode (emails will be logged only)'
);
console.warn(
'💡 To enable real emails, configure Mailgun credentials in .env.local'
);
} else {
console.warn(
'📧 Mailgun Service: Configured for production with domain:',
status.domain
);
}
}
private getVerificationEmailTemplate(verificationUrl: string): EmailTemplate {
return {
subject: 'Verify Your Email - Medication Reminder',
html: `
Verify Your Email Address
Thank you for signing up for Medication Reminder! Please click the button below to verify your email address:
Or copy and paste this link into your browser:
${verificationUrl}
This link will expire in 24 hours.
`,
text: `
Verify Your Email - Medication Reminder
Thank you for signing up! Please verify your email by visiting:
${verificationUrl}
This link will expire in 24 hours.
`,
};
}
private getPasswordResetEmailTemplate(resetUrl: string): EmailTemplate {
return {
subject: 'Reset Your Password - Medication Reminder',
html: `
Reset Your Password
You requested to reset your password. Click the button below to set a new password:
Or copy and paste this link into your browser:
${resetUrl}
This link will expire in 1 hour. If you didn't request this, please ignore this email.
`,
text: `
Reset Your Password - Medication Reminder
You requested to reset your password. Visit this link to set a new password:
${resetUrl}
This link will expire in 1 hour. If you didn't request this, please ignore this email.
`,
};
}
async sendEmail(to: string, template: EmailTemplate): Promise {
try {
// Production Mailgun API call
const formData = new FormData();
formData.append(
'from',
`${this.config.fromName} <${this.config.fromEmail}>`
);
formData.append('to', to);
formData.append('subject', template.subject);
formData.append('html', template.html);
if (template.text) {
formData.append('text', template.text);
}
const response = await fetch(
`${this.config.baseUrl}/${this.config.domain}/messages`,
{
method: 'POST',
headers: {
Authorization: `Basic ${btoa(`api:${this.config.apiKey}`)}`,
},
body: formData,
}
);
if (!response.ok) {
const errorText = await response.text();
throw new Error(`Mailgun API error: ${response.status} - ${errorText}`);
}
const result = await response.json();
console.warn('📧 Email sent successfully via Mailgun:', {
to,
subject: template.subject,
messageId: result.id,
});
return true;
} catch (error: unknown) {
console.error('Email sending failed:', error);
return false;
}
}
async sendVerificationEmail(email: string, token: string): Promise {
const verificationUrl = `${getAppConfig().baseUrl}/verify-email?token=${token}`;
const template = this.getVerificationEmailTemplate(verificationUrl);
return this.sendEmail(email, template);
}
async sendPasswordResetEmail(email: string, token: string): Promise {
const resetUrl = `${getAppConfig().baseUrl}/reset-password?token=${token}`;
const template = this.getPasswordResetEmailTemplate(resetUrl);
return this.sendEmail(email, template);
}
// Get configuration status for debugging
getConfigurationStatus(): {
configured: boolean;
mode: 'development' | 'production';
domain: string;
fromEmail: string;
} {
const configured =
!!this.config.apiKey &&
!!this.config.domain &&
!!this.config.baseUrl &&
!!this.config.fromEmail &&
!!this.config.fromName;
const mode: 'development' | 'production' = configured
? 'production'
: 'development';
return {
configured,
mode,
domain: this.config.domain,
fromEmail: this.config.fromEmail,
};
}
}
export const mailgunService = new MailgunService();