Files
gowtham-darkseid 44ea4d2e64 feat: Complete Mail Composer with EmailJS integration
- 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
2025-09-09 21:17:46 +05:30

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
};
}
});