Running e-mail for a Frappe or ERPNext site usually means SMTP credentials, IMAP polling and a mail provider in between. This app replaces both for sites whose domains are on Cloudflare. Outgoing mail goes from Frappe's override_email_send hook straight to the Cloudflare Email Sending REST API. Incoming mail arrives from the Cloudflare email relay, a Worker that pushes each message to the site over a signed HTTPS webhook, and is handed to Frappe's own InboundMail, the same path IMAP polling uses. Append To, auto-replies, attachments, notifications and reply threading behave as they do for a mailbox.
It is the Frappe adapter of Avunu's Cloudflare Email suite, beside the relay, the Odoo module mail_cloudflare and the WordPress plugin.
Full documentation: docs.avunu.net/cloudflare-email-delivery/docs/.
- No SMTP to manage. An Email Domain with Send via Cloudflare holds a Cloudflare account ID and API token instead of SMTP settings, and saving it verifies the token.
- No IMAP polling. An incoming Email Account on that domain gets a Webhook URL and a Webhook Secret when it is saved. The relay posts every message to the URL; the app checks the HMAC signature and the recipient domain, then creates the Communication (and the Append To document) as Frappe does for a mailbox.
- Threading that survives Cloudflare. Cloudflare replaces the
Message-IDof every message it sends. Frappe's own id is added toReferences, and inbound replies are matched onReferencesas well asIn-Reply-To, so a reply lands on the right document. - Attachments, inline images (by
Content-ID),Reply-Toand the headers Cloudflare allows (In-Reply-To,References,X-*,Precedenceand others) are sent. - Rate limits and transient errors are retried briefly; an invalid token fails the rest of the batch at once; recipients Cloudflare bounces or suppresses up front fail the Email Queue entry with the reason.
- Copy and regenerate buttons for the webhook credentials on the Email Account form. Only a System Manager can see or regenerate the secret.
- Mixed setups work: accounts on other domains keep using SMTP or Frappe Mail.
- The webhook processes mail as a disabled, least-privilege user, never as Administrator.
bench get-app https://github.com/Avunu/cloudflare_email_delivery --branch version-16
bench --site <site> install-app cloudflare_email_deliveryUntil the first release creates the version-16 branch, install from main instead: bench get-app https://github.com/Avunu/cloudflare_email_delivery --branch main.
You need a Cloudflare account on the Workers Paid plan, with the domain onboarded for Email Sending and Email Routing enabled on its zone, and an API token with Email Sending: Edit. For incoming mail the site must be reachable over https with host_name set in its site config (the webhook URL is built from it), and the relay needs a tenant entry for the site.
- On the Email Domain, tick Send via Cloudflare and fill in Cloudflare Account ID and Cloudflare API Token. Saving verifies the token.
- On the Email Account, link the domain, set the address and tick Enable Outgoing. There is no password and no SMTP server to fill in.
- To receive, tick Enable Incoming, choose Append To and save. Copy the Webhook URL and, as a System Manager, the Webhook Secret from the Cloudflare Webhook buttons into the relay's tenant entry, and route the addresses to the relay Worker in the zone's Email Routing.
Every setting is described in docs/configuration.md; the steps are in docs/sending.md and docs/receiving.md.
extend_doctype_classstacks the app's controllers on Email Domain and Email Account; each one calls the stock controller for anything that is not on a Cloudflare domain. On a Cloudflare domain, the Email Domain verifies the API token instead of testing SMTP and IMAP connections, and the Email Account clears its server fields, generates the webhook key and secret once, builds the webhook URL and turns the scheduler's IMAP pull into a no-op.- The
override_email_sendhook receives each recipient's copy of an Email Queue entry. For an account on a Cloudflare domain it posts the message to the Email Sending API; for any other account it sends through Frappe Mail or SMTP, as core would. cloudflare_email_delivery.api.inboundis the webhook: a guest, POST-only endpoint that verifies the relay's HMAC signature, checks the recipient domain and passes the raw message toInboundMail, run as a disabled, least-privilege user. Each status code tells the relay whether to retry; docs/webhook.md lists them.
The design is described in docs/development/architecture.md.
-
Asynchronous bounces never reach Frappe: the
Return-Pathis Cloudflare's, and bounces go to its owncf-bouncesubdomain. Only the recipients Cloudflare rejects at send time are reported. -
Reply matching after Cloudflare's
Message-IDrewrite relies on the replying client carryingReferences, which every mainstream client does. -
Cloudflare's sending limits apply: 5 MiB per message, and at most 20 custom headers of 2 KB each and 16 KB in all. Headers outside Cloudflare's allow-list (
Disposition-Notification-Toand others) are dropped. Its 50-recipient limit does not come into play, because Frappe sends each recipient a copy of its own. -
Incoming messages are limited by the site's request size:
max_file_sizein the site config, 25 MiB when it is not set. -
Frappe calls only the first
override_email_sendhook of the installed apps, so another app installed earlier that registers it replaces this app's sending. -
Bcc recipients get their copy but are not listed anywhere in the delivered message, because Frappe sends each recipient a copy of its own.
More in docs/troubleshooting.md.
- Documentation: docs.avunu.net/cloudflare-email-delivery/
- Bug reports and questions: GitHub issues
- E-mail: mail@avu.nu
nix develop # or: direnv allow
prek install # the git hooks CI runs
frappe-test # the tests, the way CI runs themThe managed files, checks and release flow are described in the app standards documentation.
The tests, the mail guard, CI and releases are described in docs/development/README.md.
MIT, Copyright (c) 2026–present Avunu LLC → license.txt
cloudflare_email_delivery/cloudflare_api.py derives from the AGPL-3.0 Odoo module of the same author and is relicensed here under MIT by its copyright holder, Avunu LLC.
