A Cloudflare Email Worker that receives emails and forwards them to Discord channels via webhook, with Markdown formatting and file attachments. Supports multiple domains routing to different Discord channels.
postal-mimeturndown for proper Discord formattingemail.txt for easy readingThis worker supports routing emails from multiple domains to different Discord channels using a single deployment.
anything@n9a.us or anything@ipcow.comDOMAIN_WEBHOOKSSet a JSON object mapping domains to webhooks:
{
"n9a.us": "https://discord.com/api/webhooks/111/aaa",
"ipcow.com": "https://discord.com/api/webhooks/222/bbb",
"example.com": "https://discord.com/api/webhooks/333/ccc"
}
In Cloudflare Dashboard:
email-to-discordDOMAIN_WEBHOOKS with the JSON aboveDEFAULT_WEBHOOK_URL as a fallbackFor each domain/channel:
cd email-to-discord-worker
npm install
npm run deploy
In Cloudflare Dashboard → Workers & Pages → email-to-discord → Settings → Variables and Secrets:
Add DOMAIN_WEBHOOKS:
{"n9a.us":"https://discord.com/api/webhooks/...","ipcow.com":"https://discord.com/api/webhooks/..."}
Optionally add DEFAULT_WEBHOOK_URL:
https://discord.com/api/webhooks/...
For each domain you want to route:
*)email-to-discordRepeat for each domain (n9a.us, ipcow.com, etc.)
Once configured:
*@n9a.us → Discord channel for n9a.us*@ipcow.com → Discord channel for ipcow.comDEFAULT_WEBHOOK_URL (if set) or rejectedThe Discord message includes:
| Feature | Behavior |
|---|---|
| Images | First image is embedded in the embed, all images are attached |
| Files | Uploaded as Discord attachments (downloadable) |
| Size Limit | Files over 8MB are skipped (Discord’s limit) |
| File Count | Maximum 10 files per message (Discord’s limit) |
| Oversized Files | Listed as “skipped” in the attachment field |
Edit EMBED_COLOR in src/index.ts:
const EMBED_COLOR = 0x5865F2; // Discord blurple
Some common colors:
0x5865F2 - Discord Blurple0x57F287 - Green0xFEE75C - Yellow0xED4245 - Red0xEB459E - FuchsiaModify the webhook payload in src/index.ts:
const payload: DiscordWebhookPayload = {
username: 'My Custom Bot Name',
avatar_url: 'https://example.com/avatar.png',
embeds: [embed],
};
If your Discord server is boosted, you can increase the file size limit:
// Level 2 boost = 50MB
const MAX_FILE_SIZE = 50 * 1024 * 1024;
// Level 3 boost = 100MB
const MAX_FILE_SIZE = 100 * 1024 * 1024;
View real-time logs:
npm run tail
Or check logs in the Cloudflare Dashboard:
email-to-discord worker| Limit | Value |
|---|---|
| Discord embed description | 4,096 characters |
| Discord field value | 1,024 characters |
| Discord embed title | 256 characters |
| Discord file size (default) | 8 MB |
| Discord files per message | 10 |
| Cloudflare email size limit | 25 MB |
Content exceeding these limits is automatically truncated or skipped.
npm run tailwrangler secret listcurl -X POST "YOUR_WEBHOOK_URL" \
-H "Content-Type: application/json" \
-d '{"content": "Test message"}'
Make sure Email Routing is properly enabled and the routing rule is active in Cloudflare Dashboard.
build 20250127203559