Node.js

Mail & Notifications

Send HTML emails and attachments with Nodemailer, use Handlebars for email templates, and send push notifications via Firebase Cloud Messaging.

Nodemailer Install & Transporter Config: Install Nodemailer and set up a reusable SMTP transporter using environment variables.
📄config/mailer.js
JS
// npm install nodemailer

const nodemailer = require('nodemailer');

const transporter = nodemailer.createTransport({
    host:   process.env.MAIL_HOST,          // e.g. smtp.gmail.com
    port:   parseInt(process.env.MAIL_PORT) || 587,
    secure: process.env.MAIL_PORT === '465', // true for 465, false for 587
    auth: {
        user: process.env.MAIL_USER,
        pass: process.env.MAIL_PASS,
    },
});

// Verify connection (optional, for debugging)
transporter.verify((error) => {
    if (error) console.error('Mailer error:', error);
    else       console.log('Mailer is ready');
});

module.exports = transporter;
Send HTML Email: Send a fully formatted HTML email with a plain-text fallback using the configured transporter.
📄services/mailService.js
JS
const transporter = require('../config/mailer');

const sendWelcomeEmail = async (toEmail, userName) => {
    const mailOptions = {
        from:    `"NeoNote App" <${process.env.MAIL_FROM}>`,
        to:      toEmail,
        subject: 'Welcome to NeoNote!',
        text:    `Hi ${userName}, welcome aboard!`,
        html:    `
            <h2>Welcome, ${userName}!</h2>
            <p>Thanks for joining <strong>NeoNote</strong>.</p>
            <a href="https://neonote.app/verify" style="
                background:#6366f1;color:#fff;padding:10px 20px;
                border-radius:6px;text-decoration:none;">
                Verify Email
            </a>
        `,
    };

    const info = await transporter.sendMail(mailOptions);
    console.log('Message sent:', info.messageId);
    return info;
};

module.exports = { sendWelcomeEmail };
Email with Attachments: Attach files from disk, a buffer, or an inline base64 string to an outgoing email.
📄services/mailService.js
JS
const sendInvoiceEmail = async (toEmail, pdfBuffer) => {
    await transporter.sendMail({
        from:    `"NeoNote" <${process.env.MAIL_FROM}>`,
        to:      toEmail,
        subject: 'Your Invoice',
        html:    '<p>Please find your invoice attached.</p>',
        attachments: [
            {
                // Attach from file path
                filename: 'terms.pdf',
                path:     './storage/terms.pdf',
            },
            {
                // Attach from Buffer (e.g. dynamically generated PDF)
                filename:    'invoice.pdf',
                content:     pdfBuffer,
                contentType: 'application/pdf',
            },
            {
                // Inline image in HTML body
                filename: 'logo.png',
                path:     './public/logo.png',
                cid:      'logo@neonote',   // referenced as <img src="cid:logo@neonote">
            },
        ],
    });
};
Email Templates with Handlebars: Use nodemailer-express-handlebars to render .hbs template files with dynamic data. Install with npm install nodemailer-express-handlebars hbs.
📄config/mailer.js
JS
const hbs = require('nodemailer-express-handlebars');
const path = require('path');

transporter.use('compile', hbs({
    viewEngine: {
        extName:       '.hbs',
        partialsDir:   path.resolve('./views/emails/partials'),
        defaultLayout: false,
    },
    viewPath: path.resolve('./views/emails'),
    extName:  '.hbs',
}));

// Send using template
await transporter.sendMail({
    from:     `"NeoNote" <${process.env.MAIL_FROM}>`,
    to:       'user@example.com',
    subject:  'Reset Password',
    template: 'reset-password',       // views/emails/reset-password.hbs
    context: {
        name:      'John',
        resetLink: 'https://neonote.app/reset?token=abc123',
    },
});
Firebase Cloud Messaging (FCM): Send push notifications to mobile or web clients using the Firebase Admin SDK. Install with npm install firebase-admin.
📄config/firebase.js
JS
const admin = require('firebase-admin');
const serviceAccount = require('./serviceAccountKey.json');

admin.initializeApp({
    credential: admin.credential.cert(serviceAccount),
});

module.exports = admin;
📄services/pushService.js
JS
const admin = require('../config/firebase');

// Send to a single device
const sendPushNotification = async (deviceToken, title, body, data = {}) => {
    const message = {
        token: deviceToken,
        notification: { title, body },
        data,                          // custom key-value pairs
        android: { priority: 'high' },
        apns: { payload: { aps: { sound: 'default' } } },
    };

    const response = await admin.messaging().send(message);
    console.log('FCM response:', response);
    return response;
};

// Send to a topic (multiple subscribers)
const sendToTopic = async (topic, title, body) => {
    await admin.messaging().send({
        topic,
        notification: { title, body },
    });
};

module.exports = { sendPushNotification, sendToTopic };