mirror of
https://github.com/Gowtham-Darkseid/MailComposer.git
synced 2026-04-15 16:08:27 +02:00
44ea4d2e64
- Rich email composer with formatting tools (bold, italic, underline, links) - Multi-recipient support (To, CC, BCC fields) - File attachments with drag & drop support - Priority levels and email validation - Draft management with auto-save and cloud sync - Real email sending via EmailJS integration - Responsive design for mobile and desktop - Comprehensive error handling and fallback modes - Complete documentation and setup guides - Firebase integration ready for advanced features Features: ✅ Real email sending (EmailJS) ✅ Rich text editor ✅ File attachments ✅ Draft management ✅ Form validation ✅ Responsive UI ✅ Error handling ✅ Documentation
181 lines
4.6 KiB
JavaScript
181 lines
4.6 KiB
JavaScript
const {onRequest, onCall} = require("firebase-functions/v2/https");
|
|
const {logger} = require("firebase-functions");
|
|
const admin = require('firebase-admin');
|
|
const nodemailer = require('nodemailer');
|
|
const cors = require('cors')({origin: true});
|
|
|
|
// Initialize Firebase Admin
|
|
admin.initializeApp();
|
|
|
|
// Configure your email service (Gmail example)
|
|
// You'll need to enable "Less secure app access" or use App Passwords
|
|
const transporter = nodemailer.createTransporter({
|
|
service: 'gmail',
|
|
auth: {
|
|
user: process.env.GMAIL_USER, // Set in Firebase Functions config
|
|
pass: process.env.GMAIL_PASSWORD // Set in Firebase Functions config
|
|
}
|
|
});
|
|
|
|
// Alternative configuration for other email services
|
|
/*
|
|
const transporter = nodemailer.createTransporter({
|
|
host: 'smtp.your-email-provider.com',
|
|
port: 587,
|
|
secure: false,
|
|
auth: {
|
|
user: process.env.EMAIL_USER,
|
|
pass: process.env.EMAIL_PASSWORD
|
|
}
|
|
});
|
|
*/
|
|
|
|
// Send Email Cloud Function
|
|
exports.sendEmail = onCall(async (request) => {
|
|
const data = request.data;
|
|
|
|
try {
|
|
// Validate required fields
|
|
if (!data.to || !data.subject || !data.message) {
|
|
throw new Error('Missing required fields: to, subject, or message');
|
|
}
|
|
|
|
// Validate email addresses
|
|
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
const validateEmails = (emails) => {
|
|
return emails.every(email => emailRegex.test(email.trim()));
|
|
};
|
|
|
|
if (!validateEmails(data.to)) {
|
|
throw new Error('Invalid email addresses in "to" field');
|
|
}
|
|
|
|
if (data.cc && !validateEmails(data.cc)) {
|
|
throw new Error('Invalid email addresses in "cc" field');
|
|
}
|
|
|
|
if (data.bcc && !validateEmails(data.bcc)) {
|
|
throw new Error('Invalid email addresses in "bcc" field');
|
|
}
|
|
|
|
// Prepare email options
|
|
const mailOptions = {
|
|
from: process.env.GMAIL_USER || 'your-email@gmail.com',
|
|
to: data.to.join(', '),
|
|
subject: data.subject,
|
|
html: data.message,
|
|
priority: data.priority || 'normal'
|
|
};
|
|
|
|
// Add CC and BCC if provided
|
|
if (data.cc && data.cc.length > 0) {
|
|
mailOptions.cc = data.cc.join(', ');
|
|
}
|
|
|
|
if (data.bcc && data.bcc.length > 0) {
|
|
mailOptions.bcc = data.bcc.join(', ');
|
|
}
|
|
|
|
// Set priority header
|
|
if (data.priority === 'high') {
|
|
mailOptions.priority = 'high';
|
|
mailOptions.headers = { 'X-Priority': '1' };
|
|
} else if (data.priority === 'low') {
|
|
mailOptions.priority = 'low';
|
|
mailOptions.headers = { 'X-Priority': '5' };
|
|
}
|
|
|
|
// Send the email
|
|
const info = await transporter.sendMail(mailOptions);
|
|
|
|
logger.info('Email sent successfully:', info.messageId);
|
|
|
|
// Log to Firestore for tracking
|
|
await admin.firestore().collection('emailLogs').add({
|
|
to: data.to,
|
|
cc: data.cc || [],
|
|
bcc: data.bcc || [],
|
|
subject: data.subject,
|
|
messageId: info.messageId,
|
|
timestamp: admin.firestore.FieldValue.serverTimestamp(),
|
|
status: 'sent'
|
|
});
|
|
|
|
return {
|
|
success: true,
|
|
messageId: info.messageId,
|
|
message: 'Email sent successfully'
|
|
};
|
|
|
|
} catch (error) {
|
|
logger.error('Error sending email:', error);
|
|
|
|
// Log failed attempt
|
|
await admin.firestore().collection('emailLogs').add({
|
|
to: data.to,
|
|
subject: data.subject,
|
|
error: error.message,
|
|
timestamp: admin.firestore.FieldValue.serverTimestamp(),
|
|
status: 'failed'
|
|
});
|
|
|
|
return {
|
|
success: false,
|
|
error: error.message
|
|
};
|
|
}
|
|
});
|
|
|
|
// Get Email Logs (for admin purposes)
|
|
exports.getEmailLogs = onCall(async (request) => {
|
|
try {
|
|
const snapshot = await admin.firestore()
|
|
.collection('emailLogs')
|
|
.orderBy('timestamp', 'desc')
|
|
.limit(50)
|
|
.get();
|
|
|
|
const logs = [];
|
|
snapshot.forEach(doc => {
|
|
logs.push({
|
|
id: doc.id,
|
|
...doc.data()
|
|
});
|
|
});
|
|
|
|
return { success: true, logs };
|
|
} catch (error) {
|
|
logger.error('Error getting email logs:', error);
|
|
return { success: false, error: error.message };
|
|
}
|
|
});
|
|
|
|
// Health check endpoint
|
|
exports.healthCheck = onRequest(async (req, res) => {
|
|
cors(req, res, () => {
|
|
res.json({
|
|
status: 'ok',
|
|
timestamp: new Date().toISOString(),
|
|
service: 'Mail Composer Functions'
|
|
});
|
|
});
|
|
});
|
|
|
|
// Test email configuration
|
|
exports.testEmailConfig = onCall(async (request) => {
|
|
try {
|
|
// Verify transporter configuration
|
|
await transporter.verify();
|
|
return {
|
|
success: true,
|
|
message: 'Email configuration is valid'
|
|
};
|
|
} catch (error) {
|
|
logger.error('Email configuration test failed:', error);
|
|
return {
|
|
success: false,
|
|
error: error.message
|
|
};
|
|
}
|
|
});
|