Skip to content

jayqi/cloudmailin-discord-webhook-bridge

Repository files navigation

cloudmailin-discord-webhook-bridge

A bridge to send inbound email from CloudMailin to a Discord channel webhook, deployed as a Cloudflare Worker.

Created with assistance from OpenAI's ChatGPT and Codex.

Environment variables

Requires the following two environment variables

  • CLOUDMAILIN_BASIC_AUTH — the user:password pair used for basic auth in the CloudMailin webhook URL.
  • DISCORD_WEBHOOK_URL — provided by Discord. Can be found by going to "Edit Channel" > "Integrations" > "Webhooks" > specific webhook > "Copy Webhook URL".

For local development, copy .dev.vars.example to .dev.vars and fill in your values so wrangler dev can read them. For deployed environments, add the secrets to your Worker with:

npx wrangler secret put CLOUDMAILIN_BASIC_AUTH
npx wrangler secret put DISCORD_WEBHOOK_URL

Wrangler will prompt you for each value and store them securely on Cloudflare.

Deploy

Run

npm run deploy

The exposed webhook endpoint for the bridge is https://<your-worker-domain>/webhooks/cloudmailin.

Set the CloudMailin target URL to include basic auth:

https://user:password@<your-worker-domain>/webhooks/cloudmailin

This worker expects the CloudMailin JSON POST format. It sends the plain field to Discord, splitting into multiple 2,000-character messages when needed.

Discord message format

The Discord message includes key email headers plus as much of the plain body as fits. Example:

From: `Message Sender <sender@example.com>`
Subject: **Test Subject**
Date: `Mon, 16 Jan 2012 17:00:01 +0000`
Attachments: `2` (file.txt, file.txt)

This is a test email message.

If the plain body exceeds Discord's 2,000 character limit, the worker sends multiple sequential Discord messages. Chunking happens on word boundaries when possible. When multiple messages are required, each message includes a part indicator after the header (and at the top of continuation messages), like [part 1/3]. Discord webhook requests are sent with ?wait=true so the Worker waits for message creation before posting the next chunk. If Discord responds with 429 or a 5xx, the Worker retries with exponential backoff and honors Retry-After when provided.

Endpoints

  • /health — health check for the service
  • /webhooks/cloudmailin — endpoint that accepts inbound email payloads from CloudMailin

About

A bridge to send inbound emails via CloudMailin to a Discord channel webhook, deployed as a Cloudflare Worker.

Resources

License

Stars

Watchers

Forks

Contributors