trasherdk / emailjs

html emails and attachments to any smtp server with nodejs
MIT License
0 stars 0 forks source link

Snippet: Example e-mail sending class #4

Open trasherdk opened 2 years ago

trasherdk commented 2 years ago

Code to test relaying mass email through primary mail server.

import type { SMTPConnectionOptions } from 'emailjs';
import { Message, SMTPClient } from 'emailjs';
import PQueue from 'p-queue';

export type AddressList = {
    from: string;
    to: string[];
};

/** Internal configuration used by emailjs to send mail, see https://www.npmjs.com/package/emailjs for all options. */
export type EmailConnectionConfig = Partial<SMTPConnectionOptions>;

export default class Emailer {
    /** stop sending mail after this many items are in the queue */
    private readonly mailQueueMaxSize = 512;

    /** The minimum amount of time between sending each email. */
    private readonly globalMailThrottle = 750;

    // throttle mail sending using a promise queue
    private readonly mailQueue = new PQueue({ concurrency: 1, interval: this.globalMailThrottle, intervalCap: 1 });

    private client: SMTPClient;

    constructor(options: EmailConnectionConfig) {
        this.client = new SMTPClient(options);
    }

    public async send(addresses: AddressList, subject: string, text: string) {
        if (!addresses) {
            console.warn(`Not sending email. Address list looks falsey.`);
            return;
        }

        const from = addresses.from;

        if (!from) {
            console.warn(`Not sending email. No from address is configured.`);
            return;
        }

        if (addresses.to.length === 0) {
            console.warn(`Not sending email. No addresses are configured to send.`);
            return;
        }

        const to = addresses.to.join(', ');
        if (this.mailQueue.size >= this.mailQueueMaxSize) {
            console.error(
                `Dropping outgoing email. There are currently too many items in the email queue. (Queue size= ${this.mailQueue.size}, maximum=${this.mailQueueMaxSize})`
            );
            return;
        }

        await new Promise<void>(resolve => {
            const mailTask = async () => {
                try {
                    console.log(`Sending email to ${to}...`);
                    await this.client.sendAsync(
                        new Message({
                            from,
                            to,
                            subject,
                            text,
                            'content-type': text.startsWith('<!DOCTYPE html') ? 'text/html; charset="UTF-8"' : undefined,
                        })
                    );
                    console.log(`Sending email to ${to}  [SENT]`);
                    console.log(`There are`, this.mailQueue.size, 'items left in the mail queue');
                    resolve();
                } catch (err) {
                    console.error('Error sending email!', `(Subject: "${subject}")`);
                    console.error(err);

                    console.log('Putting this email to the back of the send queue...');
                    void this.mailQueue.add(mailTask);
                }
            };
            void this.mailQueue.add(mailTask);
        });
    }
}

Source: https://github.com/eleith/emailjs/issues/315#issuecomment-1110206280

ecker00 commented 1 year ago

This seems like quite a nice wrapper, maybe a good example implementation to include in the main repo?

trasherdk commented 1 year ago

@ecker00 I got the example from the main repo, linked abowe as Source https://github.com/eleith/emailjs/issues/315#issuecomment-1110206280