Skip to content

Configuration Reference

Ra's al Ghul edited this page Aug 9, 2026 · 3 revisions

Configuration Reference

Mailbridge is configured primarily through environment variables in .env, with additional Cloudflare Worker bindings and secrets configured through wrangler.toml and Wrangler secrets.

This reference assumes the deployment model described in Quick Start:

  • Inbound mail is received by Cloudflare Email Routing.
  • The Cloudflare Worker encrypts inbound mail and stores it temporarily in R2.
  • Cloudflare Queues deliver references to the Mailbridge webhook.
  • Mailbridge decrypts, scans, and forwards inbound mail to a local SMTP server.
  • Trusted local systems can submit outbound mail to the Mailbridge SMTP relay.
  • The SMTP relay is unauthenticated but restricted by allowed source CIDRs.
  • Outbound relay delivery uses Cloudflare Email Service through the Worker.

Example .env

# Node App Configuration
PORT=3090
SMTP_RELAY_PORT=2525
SMTP_RELAY_SOCKET_TIMEOUT_MS=120000
SMTP_RELAY_MAX_MESSAGE_BYTES=52428800
MAILBRIDGE_VERBOSE_LOGGING=true
MAILBRIDGE_HOSTNAME=mailbridge.example.com
QUEUE_MAX_ATTEMPTS=20
DATA_DIR=/app/data
SECRETS_DB_PATH=/app/secrets/secrets.db
QUEUE_MASTER_KEY=replace_with_generated_base64_key
MAILBRIDGE_PRIVATE_KEY_PATH=/app/secrets/mailbridge-r2-private.pem
AUDIT_LOG_RETENTION_DAYS=1

# Optional in-container Cloudflare Tunnel
CLOUDFLARED_ENABLED=false
CLOUDFLARED_TUNNEL_TOKEN=
CLOUDFLARED_LOGLEVEL=info

# Worker -> Mailbridge webhook authentication
WEBHOOK_SECRET=replace_with_generated_shared_secret

# Local Mail Server Configuration
LOCAL_MAIL_HOST=mail.internal.example
LOCAL_MAIL_PORT=25
LOCAL_MAIL_SECURE=false
LOCAL_MAIL_REQUIRE_TLS=false
LOCAL_MAIL_TLS_REJECT_UNAUTHORIZED=false
LOCAL_MAIL_TLS_SERVERNAME=
LOCAL_MAIL_TLS_CA_FILE=

# Outbound Relay Provider
RELAY_UPSTREAM_PROVIDER=cloudflare
RELAY_API_KEY=
RELAY_FROM_FALLBACK=postmaster@example.com
RESEND_BASE_URL=https://api.resend.com
MAILGUN_DOMAIN=
MAILGUN_BASE_URL=https://api.mailgun.net
CLOUDFLARE_SEND_WORKER_URL=https://mailbridge-worker.example.workers.dev/api/send/email

# Dedicated Mailbridge -> Worker outbound authentication
CLOUDFLARE_SEND_WEBHOOK_SECRET=replace_with_separate_outbound_secret

# Unauthenticated SMTP Relay
SMTP_RELAY_ENABLED=true
SMTP_RELAY_VERBOSE_LOGGING=true
SMTP_RELAY_INJECT_HEADERS=true
SMTP_RELAY_REQUIRE_TLS=false
SMTP_RELAY_ALLOW_INSECURE=true
SMTP_RELAY_ALLOWED_CIDRS=192.168.1.0/24,127.0.0.1/32,::1/128
SMTP_RELAY_TLS_CERT_FILE=
SMTP_RELAY_TLS_KEY_FILE=
SMTP_RELAY_TLS_CA_FILE=

# SpamAssassin
SPAMASSASSIN_MODE=local
POSTMARK_SPAMCHECK_URL=https://spamcheck.postmarkapp.com/filter
SPAMD_HOST=127.0.0.1
SPAMD_PORT=783
SPAMD_STARTUP_ATTEMPTS=30
SPAMC_TIMEOUT_MS=10000
SPAMC_FAIL_OPEN=false
SA_BLOCK_THRESHOLD=12
SA_QUESTIONABLE_THRESHOLD=5
SPAM_SCL_SCORE=9
SPAM_SUBJECT_TAG=[SPAM]

# Optional Spamhaus Intelligence API Checks
SPAMHAUS_ENABLED=false
SPAMHAUS_USERNAME=
SPAMHAUS_PASSWORD=
SPAMHAUS_FAIL_OPEN=true

# Optional AI Secondary Screening
AI_ENABLED=false
AI_API_KEY=
AI_MODEL=gpt-5.4-nano
AI_BASE_URL=
AI_INPUT_SCOPE=headers
AI_MAX_INPUT_CHARS=20000

Core Service Configuration

These settings control the Mailbridge Node.js service, local storage, retry behavior, and operational logging.

Variable Required Default Description
PORT No 3090 HTTP port used by the Mailbridge webhook and health endpoint.
SMTP_RELAY_PORT No 2525 SMTP listener port used when outbound relay is enabled.
SMTP_RELAY_SOCKET_TIMEOUT_MS No 120000 Maximum SMTP relay socket inactivity timeout in milliseconds.
MAILBRIDGE_VERBOSE_LOGGING No true Enables verbose application logging. Accepted true values include true, 1, yes, and on.
MAILBRIDGE_HOSTNAME No mailbridge.example.com Hostname used when identifying the Mailbridge relay in generated outbound metadata and logs.
QUEUE_MAX_ATTEMPTS No 20 Maximum number of local retry attempts before a queued delivery is no longer retried.
DATA_DIR No Application data directory Directory containing audit data and encrypted retry queue files. Docker deployments should use /app/data.
SECRETS_DB_PATH No Application secrets/secrets.db SQLite path containing active queue secret material. Docker deployments should use /app/secrets/secrets.db.
QUEUE_MASTER_KEY Yes None Base64 master key used to protect locally queued retry messages. Generate once per deployment and protect it as a secret.
MAILBRIDGE_PRIVATE_KEY_PATH Required for encrypted inbound R2 delivery None Path to the RSA private key Mailbridge uses to decrypt Worker-encrypted inbound mail.
AUDIT_LOG_RETENTION_DAYS No 1 in example config Number of days to retain audit records.

Runtime storage layout

With the recommended Docker volume mounts:

data/
├── mailbridge.db
└── queue/
    └── <queued-message-id>.eml

secrets/
├── secrets.db
└── mailbridge-r2-private.pem

Purpose of each item:

Path Purpose Sensitivity
data/mailbridge.db Audit-only SQLite database. Sensitive operational metadata.
data/queue/*.eml Encrypted retry queue items created for temporary delivery failures. Encrypted but still sensitive.
secrets/secrets.db Queue secret material used to access queued messages. Highly sensitive.
secrets/mailbridge-r2-private.pem Private key used to decrypt inbound mail encrypted by the Worker. Critical secret.

Generate required local secrets

mkdir -p data/queue secrets

export QUEUE_MASTER_KEY="$(openssl rand -base64 32 | tr -d '\n')"
export WEBHOOK_SECRET="$(openssl rand -base64 48 | tr -d '\n')"

openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 \
  -out secrets/mailbridge-r2-private.pem

openssl rsa -pubout \
  -in secrets/mailbridge-r2-private.pem \
  -out secrets/mailbridge-r2-public.pem

chmod 600 secrets/mailbridge-r2-private.pem

Do not commit generated keys, .env, database files, or queue contents.


Cloudflare Tunnel Configuration

Mailbridge can optionally launch cloudflared inside the same container. This is useful when the container itself should expose the webhook endpoint publicly without directly publishing port 3090 to the internet.

Variable Required Default Description
CLOUDFLARED_ENABLED No false Starts cloudflared inside the container when enabled.
CLOUDFLARED_TUNNEL_TOKEN When enabled None Cloudflare Tunnel token used by the in-container connector.
CLOUDFLARED_LOGLEVEL No info Cloudflared logging level.

Container-managed tunnel example

CLOUDFLARED_ENABLED=true
CLOUDFLARED_TUNNEL_TOKEN=replace_with_cloudflare_tunnel_token
CLOUDFLARED_LOGLEVEL=info

The tunnel public hostname should route to:

http://localhost:3090

Host-managed tunnel example

When cloudflared runs outside the Mailbridge container:

CLOUDFLARED_ENABLED=false
CLOUDFLARED_TUNNEL_TOKEN=

Do not configure two tunnel connectors for the same hostname unless that is intentional.


Webhook Authentication

Inbound webhook requests from the Cloudflare Worker to Mailbridge must provide the configured shared secret.

Variable Required Default Description
WEBHOOK_SECRET Yes None Shared secret used to validate incoming requests to /api/webhook/email.

Mailbridge expects the Worker to send:

X-Webhook-Secret: <WEBHOOK_SECRET>

The same secret must be configured in both places:

Mailbridge .env

WEBHOOK_SECRET=replace_with_generated_shared_secret

Cloudflare Worker secret

printf '%s' "$WEBHOOK_SECRET" | \
  npx wrangler secret put WEBHOOK_SECRET --name "$WORKER_NAME"

Cloudflare outbound relay authentication

The Worker validates /api/send/email against the dedicated CLOUDFLARE_SEND_WEBHOOK_SECRET when it is configured. It falls back to WEBHOOK_SECRET only for compatibility.

Mailbridge sends its outbound Worker request using:

CLOUDFLARE_SEND_WEBHOOK_SECRET, when configured
WEBHOOK_SECRET, when CLOUDFLARE_SEND_WEBHOOK_SECRET is empty

Recommended configuration:

WEBHOOK_SECRET=replace_with_generated_shared_secret
CLOUDFLARE_SEND_WEBHOOK_SECRET=replace_with_a_different_generated_secret

Upload both values to their corresponding Worker secrets. Keeping inbound and outbound credentials distinct limits credential reuse across trust boundaries.


Local Mail Delivery Configuration

Inbound messages that pass Mailbridge processing are delivered to the configured local SMTP server.

Supported destinations include:

  • Exchange
  • Postfix
  • Haraka
  • Mailcow
  • Any SMTP-compatible local or private mail server
Variable Required Default Description
LOCAL_MAIL_HOST Yes 127.0.0.1 in service code Hostname or IP address of the local SMTP destination.
LOCAL_MAIL_PORT No 25 SMTP port of the local delivery server.
LOCAL_MAIL_SECURE No false Enables implicit TLS SMTP, typically used with port 465.
LOCAL_MAIL_REQUIRE_TLS No true Requires STARTTLS when using normal SMTP delivery.
LOCAL_MAIL_TLS_REJECT_UNAUTHORIZED No true Rejects invalid or untrusted TLS certificates.
LOCAL_MAIL_TLS_SERVERNAME No LOCAL_MAIL_HOST TLS server name override, useful when connecting by IP while validating a certificate issued to a hostname.
LOCAL_MAIL_TLS_CA_FILE No None Path to an optional PEM CA file used to trust a private SMTP certificate authority.

Production TLS example

LOCAL_MAIL_HOST=mail.internal.example
LOCAL_MAIL_PORT=25
LOCAL_MAIL_SECURE=false
LOCAL_MAIL_REQUIRE_TLS=true
LOCAL_MAIL_TLS_REJECT_UNAUTHORIZED=true
LOCAL_MAIL_TLS_SERVERNAME=mail.internal.example
LOCAL_MAIL_TLS_CA_FILE=

Internal lab example without TLS validation

LOCAL_MAIL_HOST=10.0.10.15
LOCAL_MAIL_PORT=25
LOCAL_MAIL_SECURE=false
LOCAL_MAIL_REQUIRE_TLS=false
LOCAL_MAIL_TLS_REJECT_UNAUTHORIZED=false
LOCAL_MAIL_TLS_SERVERNAME=
LOCAL_MAIL_TLS_CA_FILE=

Warning

Disabling TLS requirements or certificate validation exposes inbound mail to interception or modification between Mailbridge and the local SMTP server. Use this only for controlled testing or protected internal environments.


Outbound Provider Configuration

Mailbridge can relay outbound SMTP submissions through one of four upstream providers:

  • sendgrid
  • resend
  • mailgun
  • cloudflare
Variable Required Default Description
RELAY_UPSTREAM_PROVIDER When SMTP relay is used sendgrid Selected outbound provider: sendgrid, resend, mailgun, or cloudflare.
RELAY_API_KEY For SendGrid, Resend, or Mailgun None Provider API key. Not used for Cloudflare Email Service relay.
RELAY_FROM_FALLBACK Recommended postmaster@localhost in service code Fallback sender address used when required by outbound processing.
RESEND_BASE_URL Only for custom Resend endpoint https://api.resend.com Resend API base URL.
MAILGUN_DOMAIN For Mailgun None Sending domain configured in Mailgun.
MAILGUN_BASE_URL Only for custom Mailgun endpoint https://api.mailgun.net Mailgun API base URL.
CLOUDFLARE_SEND_WORKER_URL For Cloudflare provider None Worker endpoint handling Cloudflare Email Service sends, ending in /api/send/email.
CLOUDFLARE_SEND_WEBHOOK_SECRET Recommended for Cloudflare outbound Falls back to WEBHOOK_SECRET Dedicated secret Mailbridge sends to the Worker for outbound mail authentication.

Cloudflare Email Service example

RELAY_UPSTREAM_PROVIDER=cloudflare
RELAY_API_KEY=
RELAY_FROM_FALLBACK=postmaster@example.com
CLOUDFLARE_SEND_WORKER_URL=https://mailbridge-worker.example.workers.dev/api/send/email
CLOUDFLARE_SEND_WEBHOOK_SECRET=replace_with_dedicated_outbound_secret

Required Worker binding in wrangler.toml:

[[send_email]]
name = "EMAIL"

SendGrid example

RELAY_UPSTREAM_PROVIDER=sendgrid
RELAY_API_KEY=replace_with_sendgrid_api_key
RELAY_FROM_FALLBACK=postmaster@example.com

Resend example

RELAY_UPSTREAM_PROVIDER=resend
RELAY_API_KEY=replace_with_resend_api_key
RELAY_FROM_FALLBACK=postmaster@example.com
RESEND_BASE_URL=https://api.resend.com

Mailgun example

RELAY_UPSTREAM_PROVIDER=mailgun
RELAY_API_KEY=replace_with_mailgun_api_key
RELAY_FROM_FALLBACK=postmaster@example.com
MAILGUN_DOMAIN=mg.example.com
MAILGUN_BASE_URL=https://api.mailgun.net

SMTP Relay Configuration

The SMTP relay accepts outbound mail from trusted local applications and submits it through the selected upstream provider.

The relay is controlled by network source allowlisting and optional TLS. Mailbridge does not expose SMTP username/password authentication configuration.

Variable Required Default Description
SMTP_RELAY_ENABLED No false Enables the outbound SMTP relay listener.
SMTP_RELAY_PORT No 2525 Port used by trusted SMTP clients.
SMTP_RELAY_SOCKET_TIMEOUT_MS No 120000 SMTP session socket timeout in milliseconds.
SMTP_RELAY_MAX_MESSAGE_BYTES No 52428800 Maximum SMTP DATA size. Oversized messages receive SMTP 552.
SMTP_RELAY_VERBOSE_LOGGING No true Enables detailed outbound relay logs.
SMTP_RELAY_INJECT_HEADERS No true Adds Mailbridge relay diagnostic headers to submitted outbound messages.
SMTP_RELAY_REQUIRE_TLS No true Requires STARTTLS before accepting a submitted message unless insecure operation is explicitly allowed.
SMTP_RELAY_ALLOW_INSECURE No false Allows mail submission without TLS. Must be true for the unauthenticated non-TLS Quick Start relay.
SMTP_RELAY_ALLOWED_CIDRS Yes when relay is enabled 127.0.0.1/32,::1/128 Comma-separated IPv4 or IPv6 hosts/subnets allowed to connect to the relay.
SMTP_RELAY_TLS_CERT_FILE When TLS is configured None Path to the SMTP relay certificate PEM file.
SMTP_RELAY_TLS_KEY_FILE When TLS is configured None Path to the SMTP relay private key PEM file.
SMTP_RELAY_TLS_CA_FILE No None Optional CA PEM file for SMTP relay TLS.

Unauthenticated trusted-network relay

This matches the Quick Start deployment:

SMTP_RELAY_ENABLED=true
SMTP_RELAY_PORT=2525
SMTP_RELAY_REQUIRE_TLS=false
SMTP_RELAY_ALLOW_INSECURE=true
SMTP_RELAY_ALLOWED_CIDRS=192.168.1.0/24,127.0.0.1/32,::1/128
SMTP_RELAY_VERBOSE_LOGGING=true
SMTP_RELAY_INJECT_HEADERS=true
SMTP_RELAY_TLS_CERT_FILE=
SMTP_RELAY_TLS_KEY_FILE=
SMTP_RELAY_TLS_CA_FILE=

Replace 192.168.1.0/24 with the network that should be permitted to submit outbound mail.

Examples:

# Permit a single application server only
SMTP_RELAY_ALLOWED_CIDRS=10.0.10.25/32,127.0.0.1/32,::1/128

# Permit a trusted internal subnet
SMTP_RELAY_ALLOWED_CIDRS=10.0.20.0/24,127.0.0.1/32,::1/128

# Docker Desktop on macOS may require its bridge network
SMTP_RELAY_ALLOWED_CIDRS=192.168.1.0/24,192.168.65.0/24,127.0.0.1/32,::1/128

Never configure:

SMTP_RELAY_ALLOWED_CIDRS=0.0.0.0/0

or:

SMTP_RELAY_ALLOWED_CIDRS=::/0

Those settings effectively create an unrestricted open relay if port 2525 is reachable.

TLS-protected relay

For trusted clients that support STARTTLS:

SMTP_RELAY_ENABLED=true
SMTP_RELAY_PORT=2525
SMTP_RELAY_REQUIRE_TLS=true
SMTP_RELAY_ALLOW_INSECURE=false
SMTP_RELAY_ALLOWED_CIDRS=10.0.20.0/24,127.0.0.1/32,::1/128
SMTP_RELAY_TLS_CERT_FILE=/app/secrets/smtp-relay-cert.pem
SMTP_RELAY_TLS_KEY_FILE=/app/secrets/smtp-relay-key.pem
SMTP_RELAY_TLS_CA_FILE=

When SMTP_RELAY_REQUIRE_TLS=true and SMTP_RELAY_ALLOW_INSECURE=false, Mailbridge requires certificate and private key files to be configured at startup.


SpamAssassin Configuration

Mailbridge supports two SpamAssassin scoring modes:

Mode Description
local Starts and uses the in-container spamd daemon.
postmark Uses the Postmark SpamCheck HTTP service and does not start local spamd.
Variable Required Default Description
SPAMASSASSIN_MODE No local Selects local or postmark scoring mode.
POSTMARK_SPAMCHECK_URL For postmark mode https://spamcheck.postmarkapp.com/filter SpamCheck HTTP endpoint.
SPAMD_HOST For local mode 127.0.0.1 Host where Mailbridge connects to spamd.
SPAMD_PORT For local mode 783 Port where Mailbridge connects to spamd.
SPAMD_STARTUP_ATTEMPTS For container local mode 30 Number of startup checks before failing container startup.
SPAMC_TIMEOUT_MS No 10000 Maximum SpamAssassin request duration in milliseconds.
SPAMC_FAIL_OPEN No false Whether processing may continue when SpamAssassin is unavailable.
SA_BLOCK_THRESHOLD No 12 Spam score threshold for blocking a message.
SA_QUESTIONABLE_THRESHOLD No 5 Score threshold for marking mail as questionable.
SPAM_SCL_SCORE No 9 Spam Confidence Level header value used when spam is identified.
SPAM_SUBJECT_TAG No [SPAM] Text prepended to the subject when a message is marked as spam.

Local SpamAssassin example

SPAMASSASSIN_MODE=local
SPAMD_HOST=127.0.0.1
SPAMD_PORT=783
SPAMD_STARTUP_ATTEMPTS=30
SPAMC_TIMEOUT_MS=10000
SPAMC_FAIL_OPEN=false
SA_BLOCK_THRESHOLD=12
SA_QUESTIONABLE_THRESHOLD=5
SPAM_SCL_SCORE=9
SPAM_SUBJECT_TAG=[SPAM]

Postmark SpamCheck example

SPAMASSASSIN_MODE=postmark
POSTMARK_SPAMCHECK_URL=https://spamcheck.postmarkapp.com/filter
SPAMC_TIMEOUT_MS=10000
SPAMC_FAIL_OPEN=false
SA_BLOCK_THRESHOLD=12
SA_QUESTIONABLE_THRESHOLD=5
SPAM_SCL_SCORE=9
SPAM_SUBJECT_TAG=[SPAM]

Spamhaus Configuration

Spamhaus sender reputation checks are optional and disabled by default.

Variable Required Default Description
SPAMHAUS_ENABLED No false Enables Spamhaus Intelligence API checks.
SPAMHAUS_USERNAME When enabled None Spamhaus API username.
SPAMHAUS_PASSWORD When enabled None Spamhaus API password.
SPAMHAUS_FAIL_OPEN No true Allows mail processing to continue when Spamhaus checks fail.

Example:

SPAMHAUS_ENABLED=true
SPAMHAUS_USERNAME=replace_with_username
SPAMHAUS_PASSWORD=replace_with_password
SPAMHAUS_FAIL_OPEN=true

Mailbridge uses the original sender IP contained in the inbound Worker payload rather than treating the Cloudflare webhook request IP as the original sender.


AI Screening Configuration

Mailbridge can optionally perform a secondary AI-based spam screening pass. It is disabled by default.

Variable Required Default Description
AI_ENABLED No false Enables AI secondary screening.
AI_API_KEY When enabled None API key used by the configured AI endpoint.
AI_MODEL When enabled gpt-5.4-nano in example config Model identifier used for classification.
AI_BASE_URL Depends on provider None Optional alternate API base URL.
AI_INPUT_SCOPE No headers Controls content exposed to AI review. Supported values are headers, attachments, and full_email.
AI_MAX_INPUT_CHARS No 20000 Maximum input size sent to the AI classifier.

Headers-only example

AI_ENABLED=true
AI_API_KEY=replace_with_api_key
AI_MODEL=gpt-5.4-nano
AI_BASE_URL=
AI_INPUT_SCOPE=headers
AI_MAX_INPUT_CHARS=20000

Scope behavior

Scope Information submitted for AI review
headers Email headers only.
attachments Headers plus attachment filenames; attachment contents are not submitted.
full_email Full email content, subject to configured maximum length.

Caution

Before enabling AI screening, review privacy, confidentiality, and compliance requirements for the email content that may be transmitted to an AI provider.


Cloudflare Worker Variables, Secrets, and Bindings

Mailbridge uses a Cloudflare Worker for inbound Email Routing processing, encrypted R2 storage, Queue delivery, and optional Cloudflare Email Service outbound sends.

Worker variables

Configure these in wrangler.toml:

Variable Required Description
NODE_APP_URL Yes Public Mailbridge webhook URL. When configured as an origin without a path, the Worker appends /api/webhook/email.
MAIL_STORE_ENCRYPTION_VERSION Recommended Encryption payload version stored with R2 messages. Current encrypted flow uses v1.

Example:

[vars]
NODE_APP_URL = "https://mailbridge.example.com/api/webhook/email"
MAIL_STORE_ENCRYPTION_VERSION = "v1"

Worker secrets

Secret Required Description
WEBHOOK_SECRET Yes Authenticates inbound Worker webhook submissions to Mailbridge.
CLOUDFLARE_SEND_WEBHOOK_SECRET For Cloudflare outbound Authenticates Mailbridge requests to the Worker's /api/send/email endpoint.
MAILBRIDGE_PUBLIC_KEY_PEM For encrypted inbound storage Public key used to encrypt inbound message payloads before storing them in R2.

Upload secrets:

printf '%s' "$WEBHOOK_SECRET" | \
  npx wrangler secret put WEBHOOK_SECRET --name "$WORKER_NAME"

cat secrets/mailbridge-r2-public.pem | \
  npx wrangler secret put MAILBRIDGE_PUBLIC_KEY_PEM --name "$WORKER_NAME"

printf '%s' "$CLOUDFLARE_SEND_WEBHOOK_SECRET" | \
  npx wrangler secret put CLOUDFLARE_SEND_WEBHOOK_SECRET --name "$WORKER_NAME"

Worker bindings

Binding Resource Required For
MAIL_STORE Private R2 bucket Encrypted inbound mail storage.
MAIL_QUEUE Cloudflare Queue Inbound mail delivery from Worker to Mailbridge.
EMAIL Cloudflare Email Service binding Outbound relay when RELAY_UPSTREAM_PROVIDER=cloudflare.

Example wrangler.toml:

name = "mailbridge-worker"
main = "worker.js"
compatibility_date = "2026-05-19"
preview_urls = false

[vars]
NODE_APP_URL = "https://mailbridge.example.com/api/webhook/email"
MAIL_STORE_ENCRYPTION_VERSION = "v1"

[[r2_buckets]]
binding = "MAIL_STORE"
bucket_name = "mailbridge-inbound"

[[queues.producers]]
binding = "MAIL_QUEUE"
queue = "mailbridge-inbound"

[[queues.consumers]]
queue = "mailbridge-inbound"
max_batch_size = 10
max_batch_timeout = 5
max_retries = 3

[[send_email]]
name = "EMAIL"

The [[send_email]] block must be top-level. It must not be nested inside [[queues.consumers]].


Docker Configuration

The repository Docker Compose configuration reads .env, mounts local data and secrets directories, and publishes both HTTP and SMTP relay ports.

services:
  mail-bridge:
    build: .
    container_name: mail-bridge
    restart: unless-stopped
    ports:
      - "3090:3090"
      - "2525:2525"
    env_file: .env
    volumes:
      - "./data:/app/data"
      - "./secrets:/app/secrets"
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3090/health"]
      interval: 30s
      timeout: 10s
      retries: 3

Start Mailbridge:

docker compose up -d --build

Check health:

curl -i http://127.0.0.1:3090/health

Expected response:

OK

Protect the unauthenticated SMTP relay

Because port 2525 accepts mail without SMTP authentication in the Quick Start configuration, prefer firewall restrictions in addition to the Mailbridge CIDR allowlist.

For example, if only 10.0.20.25 should submit mail, configure:

SMTP_RELAY_ALLOWED_CIDRS=10.0.20.25/32,127.0.0.1/32,::1/128

Then restrict the host firewall so only that system can reach TCP port 2525.


Configuration Validation Checklist

Before starting Mailbridge, verify:

  • WEBHOOK_SECRET is configured in .env.
  • The Cloudflare Worker WEBHOOK_SECRET matches the Mailbridge value.
  • QUEUE_MASTER_KEY has been generated and stored securely.
  • MAILBRIDGE_PRIVATE_KEY_PATH points to the local private key.
  • The matching public key has been uploaded as MAILBRIDGE_PUBLIC_KEY_PEM.
  • LOCAL_MAIL_HOST and LOCAL_MAIL_PORT point to the inbound destination SMTP server.
  • RELAY_UPSTREAM_PROVIDER is set to the intended outbound provider.
  • When using Cloudflare outbound relay, CLOUDFLARE_SEND_WORKER_URL points to /api/send/email.
  • When using Cloudflare outbound relay, a distinct CLOUDFLARE_SEND_WEBHOOK_SECRET is configured in Mailbridge and the Worker.
  • When SMTP_RELAY_ENABLED=true, SMTP_RELAY_ALLOWED_CIDRS contains only trusted clients or networks.
  • Neither 0.0.0.0/0 nor ::/0 appears in the relay allowlist.
  • SMTP relay port 2525 is not publicly reachable.
  • .env, data/, secrets/, private keys, tokens, and database files are excluded from source control.

Clone this wiki locally