MailDesk docs
Get MailDesk
Pro

Public URL requirements for realtime push (administrator)

Realtime push needs one thing from your side that scheduled sync does not: a stable, public, HTTPS address that the email provider can call from the internet. This page explains exactly what that requirement is, why Google Pub/Sub and Microsoft Graph both insist on it, and how to verify it yourself before you run the setup assistant.

6 min read Pro

Realtime push needs one thing from your side that scheduled sync does not: a stable, public, HTTPS address that the email provider can call from the internet. This page explains exactly what that requirement is, why Google Pub/Sub and Microsoft Graph both insist on it, and how to verify it yourself before you run the setup assistant.

Available in: Pro. Realtime push (Gmail Pub/Sub and Outlook Graph) is part of the MailDesk Pro module. Basic always uses scheduled background sync and never needs a public inbound URL. The requirement on this page applies only when you enable realtime push.

This only affects realtime, never normal mail

Scheduled sync polls outbound — MailDesk reaches out to the provider, so it works behind a firewall with no public address at all. The public URL is needed only so the provider can push inbound to your webhook. If the public URL is wrong, realtime push cannot register or deliver, but scheduled sync (Gmail fallback polling every 2 minutes) keeps delivering new mail. No mail is ever lost.


What it does

Both providers deliver realtime notifications by making an HTTPS POST to a webhook on your own server:

  • Gmail uses Google Cloud Pub/Sub. The push subscription you create in your Google Cloud project posts to <your-url>/maildesk/push/gmail.
  • Outlook uses Microsoft Graph subscriptions, which post change notifications to <your-url>/maildesk/push/outlook.

For either provider to reach those routes, MailDesk has to know your public address. It reads it from the Odoo system parameter web.base.url, and builds the webhook URL as <web.base.url>/maildesk/push/gmail (or .../outlook). If web.base.url is unset, points at http://, or points somewhere the provider cannot reach, push registration fails at the preflight or validation step.

Why it matters

  • Providers refuse plain HTTP. Google Pub/Sub and Microsoft Graph both reject non-HTTPS push endpoints outright. A push subscription pointed at an http:// URL will not be accepted.
  • Self-signed certificates are rejected. The certificate on your public URL must be signed by a trusted public CA. Self-signed certificates fail the TLS handshake, and Pub/Sub then drops every delivery with a TLS error.
  • The audience must match. For Gmail, Pub/Sub signs each push with an OIDC token whose aud claim must equal the exact URL the message is delivered to. MailDesk computes that audience from web.base.url. If the saved audience and the computed webhook URL diverge, validation fails with an audience mismatch.
  • Stability matters. If your public address changes (a new tunnel, a different host, web.base.url rewritten at the next login), the provider keeps pushing to the old address and notifications silently stop. The URL must be one that stays the same.

The exact requirement

To enable realtime push, web.base.url must satisfy all of the following:

Requirement Why If it fails
Set (not empty) MailDesk cannot build a webhook URL without it Error code WEBHOOK_URL_UNSET
HTTPS (https://…, not http://) Providers refuse plain-HTTP push endpoints Error code WEBHOOK_URL_NOT_HTTPS
Valid public-CA certificate Self-signed / expired / wrong-host certs fail the TLS handshake Error code WEBHOOK_UNREACHABLE_TLS
DNS resolvable from the internet The provider must look up the hostname Error code WEBHOOK_UNREACHABLE_DNS
Reachable (responds promptly) A down tunnel or dropping firewall makes push undeliverable Error code WEBHOOK_UNREACHABLE_TIMEOUT
Stable A changing address means the provider pushes to a dead endpoint (silence — push stops arriving)

Set the public URL and freeze it

  1. Go to Settings → Technical → Parameters → System Parameters.
  2. Set web.base.url to your stable public HTTPS URL, for example https://mail.example.com (no trailing path, no trailing slash).
  3. Set web.base.url.freeze to True.

Why web.base.url.freeze = True matters

By default Odoo overwrites web.base.url with whatever host the next administrator logs in from. If an admin signs in over an internal hostname, web.base.url quietly becomes that internal address — and every provider push then targets a URL the internet cannot reach. Setting web.base.url.freeze = True pins the value so it survives logins and stays the public HTTPS address you configured.

A valid public certificate

The hostname in web.base.url must present a certificate signed by a trusted public CA — Let's Encrypt, Cloudflare, or any commercial CA all work. The certificate must cover the exact hostname the provider connects to. Self-signed certificates will be rejected by Pub/Sub. If you terminate TLS at a reverse proxy or CDN, make sure that layer serves the valid certificate and forwards /maildesk/push/gmail (and /maildesk/push/outlook) to Odoo untouched — no caching, no rewriting, no redirects.


Verify it externally

The MailDesk setup assistant probes the webhook for you during preflight, but you can — and should — confirm reachability yourself from an external machine (not from the Odoo server itself), so you are testing the same path the provider will use.

Run:

curl -sI https://your-url/maildesk/push/gmail

The expected response is:

HTTP/1.1 405 Method Not Allowed

Why 405 is the success signal

The webhook route only accepts POST requests. A plain GET (which is what curl -I sends) is therefore answered with HTTP 405 Method Not Allowed — and that 405 proves the route exists, is served by the right MailDesk controller, and is reachable over HTTPS. It is the correct result, not an error.

What the other responses mean:

  • 405 Method Not Allowed — correct. The webhook is wired up and reachable.
  • The request hangs / times out — your public URL is pointed somewhere wrong, the tunnel is down, or a firewall is dropping packets. Fix routing first (WEBHOOK_UNREACHABLE_TIMEOUT).
  • A TLS / certificate error — the certificate is expired, self-signed, or for the wrong hostname (WEBHOOK_UNREACHABLE_TLS).
  • Any other status (200, 302, 404, …) — something else is bound to that path: a CDN cache, a redirect, or the wrong module. Make sure your reverse proxy passes /maildesk/push/gmail straight to Odoo (WEBHOOK_UNEXPECTED_STATUS).

If the hostname does not resolve at all, check DNS first:

nslookup your-host

If you use split-brain DNS (the internal name differs from the external one), make sure the Odoo server resolves the same name external clients see (WEBHOOK_UNREACHABLE_DNS).


Development tunnel caveat

Tunnels such as trycloudflare.com are convenient for local development and QA, but they are ephemeral: a quick-tunnel URL is generated fresh each time and dies when the origin restarts. When the tunnel URL changes:

  • the provider keeps pushing to the old, now-dead address, so realtime notifications stop;
  • web.base.url no longer matches the live endpoint, so the OIDC audience no longer matches (AUDIENCE_MISMATCH) and you must re-run the assistant to re-align it.

For this reason the assistant offers a Developer / Test mode for short-lived tunnel setups — use it for QA only. For any real deployment, use a stable public hostname with a persistent certificate, and freeze web.base.url.

Push never blocks normal sync

Even while you are sorting out the public URL, mail keeps flowing. Every webhook error code on this page blocks only realtime registration or delivery — Gmail fallback polling keeps delivering new mail every 2 minutes, and Outlook falls back to scheduled sync, until realtime is restored. Nothing to babysit.


Error codes that point here

If the setup assistant shows one of these codes, this page is the reference for the fix:

Code Meaning Fix
WEBHOOK_URL_UNSET web.base.url is empty Set it (and freeze it) as above
WEBHOOK_URL_NOT_HTTPS URL is http://, not https:// Switch to https:// with a valid certificate
WEBHOOK_UNREACHABLE_DNS Hostname does not resolve Check DNS with nslookup; reconcile split-brain DNS
WEBHOOK_UNREACHABLE_TIMEOUT No response within 5 seconds Fix routing / tunnel / firewall; expect 405 on curl -sI
WEBHOOK_UNREACHABLE_TLS TLS handshake failed Replace with a public-CA certificate for the exact hostname
WEBHOOK_UNEXPECTED_STATUS Something other than 405 answered Pass /maildesk/push/gmail straight to Odoo, no cache/redirect