Skip to content

Cloudflare mail: the system's mailbox

com.me.mail.cloudflare gives the system its own email address (for example assistant@your-domain) on Cloudflare Email Routing:

  • members can email it, as they can text the system’s number;
  • the system sends notifications, verification codes and approved replies from it.

A small Cloudflare Email Worker, in deploy/cloudflare-mail/, does the receiving and sending:

  • Inbound, it checks the sender’s DKIM alignment, then posts the message to Me’s webhook, signed with HMAC-SHA256. Messages over 10 MB are refused.
  • Outbound, it serves POST /send. Cloudflare delivers only to verified destination addresses, so each person who should receive mail must be verified in Email Routing.

You need a domain on Cloudflare with Email Routing, Node.js (wrangler comes with npm install; run it as npx wrangler unless you installed it globally), and the Me tunnel for the webhook.

  1. Deploy the worker. In deploy/cloudflare-mail/, run npm install, then npx wrangler secret put API_TOKEN and npx wrangler secret put SIGNING_SECRET. Choose two long random strings, and keep them for step 2. Set MAIL_ADDRESS in wrangler.toml, then run npx wrangler deploy.

  2. Add the connection in Me. The check calls the worker’s /verify, so the worker must be deployed first.

    Terminal window
    me integration add com.me.mail.cloudflare --name "System mail" --address assistant@your-domain --worker-url https://<worker>.workers.dev
    # api_token and signing_secret (the worker's API_TOKEN and SIGNING_SECRET) are asked at the hidden prompt

    The answer prints the connection’s webhook URL, https://<tunnel host>/webhooks/conn_…, once the tunnel is set up (before that, only the path).

  3. Point the worker at Me. Set ME_WEBHOOK_URL in wrangler.toml to that URL, and run npx wrangler deploy again.

  4. Route the mail. In Cloudflare Email Routing, route the address to the worker, and verify each person’s address as a destination.

(The worker’s own README still says me conn add. The command is me integration add.)

  • Every message is recorded. Inbound mail lands in the inbox as email.
  • Some messages are “to the system”. A message counts as addressed to the system only when its DKIM signature aligns with the sender’s domain and it was sent to the connection’s address. A verified member’s message then gets an answer, as on the system’s number, once they turned the line on with me session line enable.
  • No BAA, so no content above Internal. Cloudflare isn’t covered by one, so notifications above that level go out as an opaque notice, and the content stays in the in-app inbox.
  • Sending through it waits for your approval (me comms send, me comms reply).
You see What to do
“The mail worker refused the API token.” The api_token doesn’t match the worker’s API_TOKEN secret
“The mail worker answered HTTP n (is it deployed at that URL?).” Check --worker-url, and npx wrangler deploy
“worker_url must be https.” Use the https://…workers.dev URL