Simplifying Email Service Configuration with Nodemailer

“Send Emails in Node.js with Typescript Using Multiple Email Service Providers”

Table of contents

Sending emails is an essential part of many applications, and configuring email providers can be a daunting task for developers. In this article, we will explore how to simplify email service configuration using Nodemailer, a popular Node.js module for sending emails.

Nodemailer provides a simple and flexible API for sending emails with support for multiple email providers. In this example, we will be using two email providers, Gmail and Mailtrap. We will create an EmailService class that will handle sending emails, and a sendEmail function that will use the EmailService class to send emails.

Let’s start by looking at the code:

import nodemailer, { SendMailOptions } from 'nodemailer';

interface EmailOptions {
    service?: string;
    host?: string;
    port?: number;
    auth: {
        user: string;
        pass: string;
    };
}

class EmailService {
    private transporter: any;

    constructor(private options: EmailOptions) {
        this.transporter = nodemailer.createTransport(options);
    }

    public async sendMail(mailOptions: SendMailOptions): Promise<void> {
        await this.transporter.sendMail(mailOptions);
    }
}

const getEmailService = (): EmailService => {
    const emailProviders: { [key: string]: () => EmailService } = {
        gmail: () =>
            new EmailService({
                service: 'gmail',
                auth: {
                    user: process.env.GMAIL_USERNAME,
                    pass: process.env.GMAIL_PASSWORD,
                },
            }),
        mailtrap: () =>
            new EmailService({
                host: process.env.MAILTRAP_HOST,
                port: 2525,
                auth: {
                    user: process.env.MAILTRAP_USERNAME,
                    pass: process.env.MAILTRAP_PASSWORD,
                },
            }),
    };

    const defaultEmailProvider =
        process.env.DEFAULT_EMAIL_PROVIDER?.toLowerCase() || 'mailtrap';

    if (!emailProviders[defaultEmailProvider]) {
        throw new Error(
            `Invalid email provider '${defaultEmailProvider}'. Supported providers are ${Object.keys(
                emailProviders
            ).join(', ')}`
        );
    }

    return emailProviders[defaultEmailProvider]();
};

const sendEmail = async (to: string | string[], subject: string, html: string): Promise<void> => {
    const emailService = getEmailService();

    const mailOptions = {
        from: process.env.EMAIL_SENDER,
        to: Array.isArray(to) ? to.join(',') : to,
        subject: subject,
        html: html,
    };

    await emailService.sendMail(mailOptions);
};

export default sendEmail;

The above code exports a function called sendEmail that takes the recipient email address(es), email subject, and HTML content of the email. It then calls the getEmailService function to retrieve an email service instance based on the default email provider specified in the environment variables. A mailOptions object is then created with email details and the sendMail function of the email service instance is called to send the email.

The getEmailService function returns an instance of the EmailService class based on the default email provider set in environment variables. The EmailService class takes an EmailOptions object with email provider details such as the service name, host, port, and authentication details.

Within the getEmailService function, an object called emailProviders is defined to map email provider names to functions that return an EmailService class instance with appropriate options. In this example, Gmail and Mailtrap email providers are defined with their respective options.

In summary, the sendEmail function sends an email using a default email provider, the EmailService class is used to send emails with nodemailer library, and the getEmailService function returns an instance of EmailService based on the default email provider set in environment variables.

Usage

import sendEmail from './sendEmail';

async function main() {
  const to = 'recipient@example.com';
  const subject = 'Test email';
  const html = '<p>This is a test email.</p>';

  await sendEmail(to, subject, html);

  console.log('Email sent!');
}

main();