My Email Worker Catchall: Backup Routing, Plus Addressing, and Subdomain Addressing

Thank you. Do I need to add both alias, primary and backup email in Destination addresses? I currently only have primary (@gmail.com) listed as Verified.

Yes. Any address that Cloudflare sends to will need to be verified.

But they are not sending to alias, only primary and backup - correct?

Correct. :+1:

Sorry, I missed your inclusion of “alias” in your previous comment.

Thank you. It seems to be working now :clap:

1 Like

Is there any way to report message as forwarded when succesfully sent via Email Worker rather than showing as Dropped?

No. This is how cloudflare handles mails through a worker. In my brain it is „mail successfully dropped to mailbox“ and it feels better. :blush:

2 Likes

Yes, that feel indeed better. Thanks.

Gmailify.com here :slight_smile: Thank you all for suggesting Gmailify as a solution previously. We are Swiss based email companies (same team) behind Migadu dot com and Gmailify dot com. We host about 1 million mailboxes globally since 2015 so we’re not new in the email space nor one man show @dariusz.wieckiewicz

We’ve made Gmailify.com because we’ve seen the same issue cloudflare suffered from recently at Migadu when forwarding to Gmail: it happens more often than one would think. I think Cloudflare just ran out of IPs to try deliveries with. With forwarding, one has to forward also spam messages because of the risk of false positives. If the destination rejects the message, if you don’t have some local storage, that message has to be dropped.

The forwarding fail-over in the worker code is great idea, and it indeed patches things similar as Gmailify, though:

  • one still relies on forwarding to reach a mailbox (we deliver the message locally)
  • single domain / mailbox setup
  • aliases/domain aliases etc?
  • password change on any of the mailboxes will break the whole thing
  • no outbound support for the forwarded domain/mailbox

What maybe is not clear is that Gmailify.com is a full-featured “email provider as an extension”, not just a forwarding “hack”. We forward only to Gmail, but also operate own outbound IP space as a RIPE member, which is accessible only from Gmail.

One not only receives mails but can also reply, as the mailbox, alias or even domain aliases, something you cannot easily do with CF at the moment. All that is managed from one place.

IMHO if you don’t need outbound service and are forwarding not-so-important messages of a single address, the worker solution is great alternative. I’d never rely solely on forwarding for company mails though. Forwarding is a hack on email, it was never an intended use case.

Hopefully it gives more info to those interested!

4 Likes

Great to have you here Dejan and great you gave some more insights. That definitely increase trust in your great service.

Great to know. I haven’t said that, just quoted. Testimonials or some stats on your website will greatest help understand that. Thanks for involving into discussion.

I refactored my solution one more time. I included a telegram notification in case gmail rejected the mail. And if the backup mail provider is rejecting aswell there is another notification to telegram. If one is interested, let me know and I will post it here.

I would very interested in seeing it! I was trying to explore the webhook route, but have not figured that out.

Thanks for the info!

you can find it here. I refactored a few other things as well, just take what you need:

for telegram you need to create your own bot in telegram. to do that, chat to @BotFather and create your bot.
within telegramBotUrl replace $TOKEN with your bot token and $ID with the chat id of the chat between you and your bot. to find more details about that, just use google.

mail-router.js
const usersMap = new Map([
    [
        ['[email protected]', '[email protected]'],
        {
            primary: '[email protected]',
            backup: '[email protected]',
        },
    ],
    [
        ['[email protected]'],
        {
            primary: '[email protected]',
            backup: '[email protected]',
        },
    ],
    [
        ['[email protected]', '[email protected]'],
        {
            primary: '[email protected]',
            backup: '[email protected]',
        },
    ],
    [
        ['[email protected]'],
        {
            primary: '[email protected]',
            backup: '[email protected]',
        },
    ],
]);

const defaultUser = {
    primary: '[email protected]',
    backup: '[email protected]',
};

const telegramBotUrl = "https://api.telegram.org/bot$TOKEN/sendMessage?chat_id=$ID&text=";

async function notifyTelegram(message) {
    await fetch(telegramBotUrl + message, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' }
    }).catch(error => {});
}

export default {
    async email(message, env, ctx) {

        let targetUser = defaultUser;

        for (const [aliases, user] of usersMap.entries()) {
            if (aliases.some(alias => alias.toLowerCase() === message.to.toLowerCase())) {
                targetUser = user;
                break;
            }
        }

        try {
            await message.forward(targetUser.primary);
        } catch (error) {
            await notifyTelegram(`Gmail rejected!\n\nFrom: ${message.from}\nTo: ${message.to}\nSubject: ${message.headers.get('subject')}\n\nGmail error: ${error.message}`);
            try {
                await message.forward(targetUser.backup);
            } catch (backupError) {
                message.setReject(`${backupError.message}\n${error.message}`);

                await notifyTelegram(`Mail fully rejected!\n\nFrom: ${message.from}\nTo: ${message.to}\nSubject: ${message.headers.get('subject')}\n\nGMX error: ${backupError.message}\n\nGmail error: ${error.message}`);
            }
        }
    }
};

and what I get from my telegram bot is:

Gmail rejected!

From: [email protected]
To: [email protected]
Subject: hidden subject

Gmail error: could not send email: Unknown error: transient error (421): 4.7.28 Gmail has detected an unusual rate of unsolicited mail originating4.7.28 from your DKIM domain [cloudflare-email.net 36]. To protect our4.7.28 users from spam, mail sent from your domain has been temporarily4.7.28 rate limited. For more information, go to4.7.28 Email sender guidelines - Google Workspace Admin Help to4.7.28 review our Bulk Email Senders Guidelines. j9-20020a5d6189000000b0033e742d4571si3732474wru.571 - gsmtp

1 Like

This is great. Took me a while to figure out the proper $ID (I was trying to use my bot ID for a bit). I now have two bots! :slight_smile:

  • One that shows errors only (gives me alerts)

  • The other shows all mail, and acts as a log (which I have silenced)

1 Like

You could also use the same chat bot and create two chat groups with it. Get the id of both groups and post your messages for log and rejects into the different groups. But two bots and direct messages to you are also working. Glad you are using it. :tada:

1 Like