Use Cloudflare to Catch All Emails

Redirect all Emails to a Worker

Email Routing > Routing Rules > Catch-all address

/**
 * @typedef {object} Env
 * @property {R2Bucket} r2
 * @property {D1Database} d1
 */

export default {
  /**
   * @param {ForwardableEmailMessage} message
   * @param {Env} env
   * 
   * This function is triggered when an email is received.
   * It saves the raw email data to R2 and metadata to D1.
   */
  async email(message, env) {
    const id = crypto.randomUUID();

    console.log('Got email from', message.from, 'to', message.to);

    const size = message.rawSize;
    const date = Date.now();

    const { readable, writable } = new FixedLengthStream(size);

    message.raw.pipeTo(writable);

    // Save raw data to r2
    try {
      await env.r2.put(`raw/${id}`, readable);
    } catch (err) {
      console.error(`Failed to put email raw data into r2`, err);
      return;
    }

    // Save metadata to d1
    try {
      await env.d1.prepare(`INSERT INTO emails (id, size, date, "from", "to") VALUES (?1, ?2, ?3, ?4, ?5)`)
        .bind(id, size, date, message.from, message.to)
        .run();
    } catch (err) {
      console.error(`Failed to put email metadata into d1`, err);
      return;
    }

    console.log('Successfully saved email', id)
  },

  /**
   * @param {ScheduledEvent} event
   * @param {Env} env
   * 
   * This function is triggered by a scheduled event (cron job).
   * It will delete emails older than 5 days.
   */
  async scheduled(event, env) {
    const time = event.scheduledTime;
    const before = time - 5 * 24 * 60 * 60 * 1000; // 5 days

    console.log(`[cron] Deleting emails before`, new Date(before));

    const query = env.d1.prepare('SELECT id FROM emails WHERE date < ?1');
    const res = await query.bind(before).all();
    const emails = res.results;

    console.log(`[cron] Deleting emails`, emails.map(e => e.id).join(', '));

    for (const e of emails) {
      await env.r2.delete(`raw/${e.id}`);
      await env.d1.prepare('DELETE FROM emails WHERE id = ?1').bind(e.id).run();
    }

    console.log(`[cron] Deleted ${emails.length} emails`);
  },
}

Configure cloudflare to redirect some Emails to a specific address

Configure GMail (jhon.doe@gmail.com) to receive some Emails

https://support.google.com/mail/answer/22370?hl=en

Tip: You can send emails from up to 99 different email addresses.

Step 1: Add an address you own

  • On your computer, open Gmail.
  • In the top right, click Settings Settings and then See all settings.
  • Click the Accounts and import or Accounts tab.
  • In the "Send mail as" section, click Add another email address.
  • Enter your name (John Doe) and the external address (jhon@my-domain.com) you want to send from (uncheck "Treat as an alias").
  • Enter the Scaleway SMTP server (smtp.tem.scaleway.com, port 465)

===============

This way you:

  • can receive emails to your custom domain email address, they will be redirected to your Gmail account
  • can use your Gmail account to send emails with your custom domain email address
  • can handle the catch-all emails with a Worker
  • don't need to pay for a custom email hosting service
  • don't need to setup a gmail application password
  • you are SPF/DKIM compliant thanks to Scaleway