0.0.8 • Published 7 months ago

cloudflare-email-router v0.0.8

Weekly downloads
-
License
MIT
Repository
github
Last release
7 months ago

Cloudflare Email Router

Support advanced routing on Cloudflare Workers.

Usage

The router serves as a middleware for the EmailKit.

Matcher

The matchers are executed in order, and the first matched handler will be executed.

The matchers can be a string (to test with message.to), a regex (to test with message.to), or a function (to test with the whole message).

The async matcher is also supported to provide more flexibility (e.g. to query the database).

Handler

The handler can be a function or another middleware, including another router.

import { CATCH_ALL, EmailKit, EmailRouter, REJECT_ALL, SizeGuard, ab2str, createMimeMessage, mailchannels, respond } from "cloudflare-email";
import { Backup } from "cloudflare-email-backup";

export interface Env {
    R2: R2Bucket;
    D1: D1Database;
    NOTIFICATION_EMAIL: string;
}

export default {
    async email(message: ForwardableEmailMessage, env: Env, ctx: ExecutionContext): Promise<void> {
        const router = new EmailRouter()
            // handle auto-sent emails
            .match(
                (m) => m.isAuto(),
                async (m) => {
                    const notification = createMimeMessage();
                    notification.setSender("admin@test.csie.cool");
                    notification.setRecipient(env.NOTIFICATION_EMAIL);
                    notification.setSubject(`Received an auto-generated email from ${m.from}`);
                    notification.addMessage({
                        contentType: "text/plain",
                        data: `Received an auto-generated email from ${m.from} to ${m.to}, as the attachment shows.`,
                    });
                    notification.addAttachment({
                        contentType: "message/rfc822",
                        data: await m.raw().then((typed) => ab2str(typed.buffer)),
                        filename: "original.eml",
                    });
                    await mailchannels(notification);
                },
            )
            // use a sub-router to handle subdomain emails
            .match(
                /@test\.csie\.cool$/,
                new EmailRouter()
                    .match(/^admin@/, async (message) => {
                        const msg = respond(message);
                        msg.addMessage({
                            contentType: "text/plain",
                            data: "Hello, I'm the admin!",
                        });
                        await message.reply(msg);
                    })
                    .match(
                        // function matchers are also supported, even async ones which query databases
                        (m) => m.from.length % 2 === 0,
                        async (message) => {
                            const msg = respond(message);
                            msg.addMessage({
                                contentType: "text/plain",
                                data: `The length of your email address is even!`,
                            });
                            await message.reply(msg);
                        },
                    )
                    .match(CATCH_ALL, async (message) => {
                        const msg = respond(message);
                        msg.addMessage({
                            contentType: "text/plain",
                            data: "The length of your email address is odd!",
                        });
                        await message.reply(msg);
                    }),
            )
            .match(...REJECT_ALL("Your email is rejected! :P"));

        const kit = new EmailKit()
            .use(new SizeGuard(10 * 1024 * 1024))
            .use(
                new Backup({
                    bucket: env.R2,
                    prefix: "backup",
                    database: env.D1,
                    table: "emails",
                }),
            )
            .use(router);

        await kit.process(message);
    },
};