Skip to content

Messages Environment Variables

.env File

# Django
DJANGO_CONFIGURATION=Production
DJANGO_SECRET_KEY=<generate-50-char-random>
DJANGO_ALLOWED_HOSTS=messages.<domain>,api.messages.<domain>,backend,localhost,127.0.0.1
DJANGO_SETTINGS_MODULE=messages.settings
PYTHONPATH=/app

# Database
DB_HOST=postgresql
DB_NAME=messages
DB_USER=messages
DB_PASSWORD=<db-password>
DB_PORT=5432

# Redis / Celery
REDIS_URL=redis://redis:6379
CELERY_BROKER_URL=redis://redis:6379

# OpenSearch
OPENSEARCH_URL=["http://opensearch:9200"]

# Object storage (MinIO)
AWS_S3_ENDPOINT_URL=http://minio:9000
AWS_S3_ACCESS_KEY_ID=messages
AWS_S3_SECRET_ACCESS_KEY=<minio-password>
AWS_S3_SIGNATURE_VERSION=s3v4
AWS_STORAGE_BUCKET_NAME=messages-media
MEDIA_BASE_URL=https://s3.messages.<domain>

# Message imports storage
STORAGE_MESSAGE_IMPORTS_ENDPOINT_URL=http://minio:9000
STORAGE_MESSAGE_IMPORTS_BUCKET_NAME=msg-imports
STORAGE_MESSAGE_IMPORTS_ACCESS_KEY=messages
STORAGE_MESSAGE_IMPORTS_SECRET_KEY=<minio-password>

# Tiered blob storage
STORAGE_MESSAGE_BLOBS_ENDPOINT_URL=http://minio:9000
STORAGE_MESSAGE_BLOBS_BUCKET_NAME=msg-blobs
STORAGE_MESSAGE_BLOBS_ACCESS_KEY=messages
STORAGE_MESSAGE_BLOBS_SECRET_KEY=<minio-password>

# Static files
STORAGES_STATICFILES_BACKEND=django.contrib.staticfiles.storage.StaticFilesStorage
DJANGO_DATA_DIR=/data

# OIDC (Keycloak — messages realm)
OIDC_RP_CLIENT_ID=messages
OIDC_RP_CLIENT_SECRET=<oidc-client-secret>
OIDC_RP_SIGN_ALGO=RS256
OIDC_RP_SCOPES=openid email
OIDC_CREATE_USER=True

OIDC_OP_JWKS_ENDPOINT=https://auth.messages.<domain>/realms/messages/protocol/openid-connect/certs
OIDC_OP_AUTHORIZATION_ENDPOINT=https://auth.messages.<domain>/realms/messages/protocol/openid-connect/auth
OIDC_OP_TOKEN_ENDPOINT=https://auth.messages.<domain>/realms/messages/protocol/openid-connect/token
OIDC_OP_USER_ENDPOINT=https://auth.messages.<domain>/realms/messages/protocol/openid-connect/userinfo
OIDC_OP_LOGOUT_ENDPOINT=https://auth.messages.<domain>/realms/messages/protocol/openid-connect/logout

OIDC_REDIRECT_ALLOWED_HOSTS=["https://auth.messages.<domain>","https://messages.<domain>"]
OIDC_AUTH_REQUEST_EXTRA_PARAMS={}
OIDC_STORE_ID_TOKEN=True
OIDC_FALLBACK_TO_EMAIL_FOR_IDENTIFICATION=True
OIDC_REDIRECT_REQUIRE_HTTPS=True

# Keycloak admin API (for mailbox/group management)
IDENTITY_PROVIDER=keycloak
KEYCLOAK_REALM=messages
KEYCLOAK_URL=https://auth.messages.<domain>
KEYCLOAK_CLIENT_ID=rest-api
KEYCLOAK_CLIENT_SECRET=<kc-rest-api-secret>
KEYCLOAK_GROUP_PATH_PREFIX=/maildomain-

# Login redirects
LOGIN_REDIRECT_URL=https://messages.<domain>
LOGIN_REDIRECT_URL_FAILURE=https://messages.<domain>
LOGOUT_REDIRECT_URL=https://messages.<domain>
ALLOW_LOGOUT_GET_METHOD=True

# Security
CSRF_TRUSTED_ORIGINS=["https://messages.<domain>","https://api.messages.<domain>"]
CORS_ALLOW_ALL_ORIGINS=False
CORS_ALLOWED_ORIGINS=["https://messages.<domain>"]

# Outbound mail (direct to Brevo relay)
MTA_OUT_MODE=relay
MTA_OUT_RELAY_HOST=smtp-relay.brevo.com:587
MTA_OUT_RELAY_USERNAME=<brevo-username>
MTA_OUT_RELAY_PASSWORD=<brevo-password>
MTA_OUT_SMTP_TLS_SECURITY_LEVEL=may

# Server-to-server API tokens (for Calendars integration)
DJANGO_SERVER_TO_SERVER_API_TOKENS=<api-token>

# MDA shared secret (backend ↔ mta-in)
MDA_API_SECRET=<mda-secret>
MDA_API_BASE_URL=http://backend:8000/api/v1.0/

# Salt
SALT_KEY=<random-salt>

# Email brand
DJANGO_EMAIL_BRAND_NAME=Messages
DJANGO_EMAIL_HOST=mta-out
DJANGO_EMAIL_PORT=587

# Frontend (Next.js)
NEXT_PUBLIC_API_ORIGIN=https://api.messages.<domain>
NEXT_TELEMETRY_DISABLED=1
NEXT_PUBLIC_DEFAULT_LANGUAGE=en-US
NEXT_PUBLIC_LANGUAGES=[["en-US","English"],["fr-FR","Français"]]
NEXT_PUBLIC_THEME_CONFIG={"theme":"white-label"}
FRONTEND_THEME=white-label
FRONTEND_SILENT_LOGIN_ENABLED=True
MESSAGES_FRONTEND_BACKEND_SERVER=172.29.0.10:8000

# AI features (disabled)
FEATURE_AI_SUMMARY=False
FEATURE_AI_AUTOLABELS=False
AI_BASE_URL=
AI_API_KEY=
AI_MODEL=

# Logging
LOGGING_LEVEL_HANDLERS_CONSOLE=INFO
LOGGING_LEVEL_LOGGERS_ROOT=INFO
LOGGING_LEVEL_LOGGERS_APP=INFO

Critical Settings

Variable Why it matters
DJANGO_ALLOWED_HOSTS Must include messages.<domain> — Caddy proxies with this Host header
OIDC_CREATE_USER=True Auto-creates Messages users on first OIDC login
DJANGO_SERVER_TO_SERVER_API_TOKENS Uses DJANGO_ prefix (django-configurations convention)
FRONTEND_SILENT_LOGIN_ENABLED=True Skips ProConnect button, redirects directly to Keycloak
MESSAGES_FRONTEND_BACKEND_SERVER=172.29.0.10:8000 Static IP — avoids Caddy DNS caching issues

Generating Secrets

python3 -c "import secrets; print(secrets.token_hex(32))"