Environment Variables
This document provides a comprehensive overview of all environment variables used in the Messages application. These variables are organized by service and functionality.
Development Environment
Environment Files Structure
The application uses a new environment file structure with .defaults and .local files:
*.defaults - Committed default configurations
*.local - Gitignored local overrides (created by make bootstrap)
Available Environment Files
backend.defaults - Main Django application settings
common.defaults - Shared settings across services
frontend.defaults - Frontend configuration
postgresql.defaults - PostgreSQL database configuration
keycloak.defaults - Keycloak configuration
mta-in.defaults - Inbound mail server settings
mta-out.defaults - Outbound mail server settings
crowdin.defaults - Translation service configuration
Core Application Configuration
Django Settings
| Variable |
Default |
Description |
Required |
DJANGO_CONFIGURATION |
Development |
Django configuration class to use (Development, Production, Test, etc.) |
Required |
DJANGO_SECRET_KEY |
None |
Secret key for cryptographic signing |
Required |
DJANGO_ALLOWED_HOSTS |
[] |
List of allowed hostnames |
Required |
DJANGO_SETTINGS_MODULE |
messages.settings |
Django settings module |
Required |
DJANGO_SUPERUSER_PASSWORD |
admin |
Default superuser password for development |
Dev |
DJANGO_DATA_DIR |
/data |
Base directory for data storage |
Optional |
DJANGO_ADMIN_URL |
admin |
admin route (must not be ended by /) |
Optional |
Database Configuration
PostgreSQL (Main Database)
| Variable |
Default |
Description |
Required |
DATABASE_URL |
None |
Complete database URL (overrides individual DB_* vars) |
Optional |
DB_ENGINE |
django.db.backends.postgresql_psycopg2 |
Database engine |
Optional |
DB_HOST |
postgresql |
Database hostname (container name) |
Optional |
DB_NAME |
messages |
Database name |
Optional |
DB_USER |
user |
Database username |
Optional |
DB_PASSWORD |
pass |
Database password |
Optional |
DB_PORT |
5432 |
Database port |
Optional |
PostgreSQL (Keycloak)
| Variable |
Default |
Description |
Required |
POSTGRES_DB |
messages |
Keycloak database name |
Dev |
POSTGRES_USER |
user |
Keycloak database user |
Dev |
POSTGRES_PASSWORD |
pass |
Keycloak database password |
Dev |
Redis Configuration
| Variable |
Default |
Description |
Required |
REDIS_URL |
redis://redis:6379 |
Redis connection URL (internal) |
Optional |
CELERY_BROKER_URL |
redis://redis:6379 |
Celery message broker URL (internal) |
Optional |
CACHES_DEFAULT_TIMEOUT |
30 |
Default cache timeout in seconds |
Optional |
Note: For external Redis access, use localhost:8913. For internal container communication, use redis:6379.
OpenSearch Configuration
| Variable |
Default |
Description |
Required |
OPENSEARCH_URL |
["http://opensearch:9200"] |
OpenSearch hosts list |
Optional |
OPENSEARCH_TIMEOUT |
20 |
OpenSearch query timeout (seconds) for unitary requests |
Optional |
OPENSEARCH_BULK_TIMEOUT |
60 |
OpenSearch request timeout (seconds) applied to bulk indexation calls. Raise it if full reindex (make search-index) hits timeouts on large payloads. |
Optional |
OPENSEARCH_BULK_MAX_BYTES |
26_214_400 |
Flush threshold (bytes) for bulk indexation payloads; default 25 MiB. Once accumulated actions exceed this, opensearch-py emits a sub-chunk HTTP request. Note: this is a batching threshold, not a per-document cap — a single oversized document is still sent as its own chunk. Keep well under the OpenSearch server http.max_content_length |
Optional |
OPENSEARCH_BULK_CHUNK_SIZE |
50 |
Number of thread documents (and their child message documents) accumulated before a bulk flush in reindex_bulk_threads. Lower values reduce per-request cluster pressure (heap, queue depth) at the cost of more round-trips. Lower this if you see 503s on bulk requests. |
Optional |
OPENSEARCH_MAX_RETRIES |
3 |
Transport-level retry budget on the OpenSearch client. The opensearch-py transport already retries on 502/503/504 (DEFAULT_RETRY_ON_STATUS); this just exposes the count so it can be raised above the library default. Whatever exhausts this budget is wrapped as TransientTransportError and handed to Celery autoretry (5 attempts, exponential backoff up to 600s). |
Optional |
OPENSEARCH_INDEX_THREADS |
True |
Enable thread indexing |
Optional |
SEARCH_REINDEX_TASKS_INTERVAL |
30 |
Interval (seconds) between Celery Beat runs of process_pending_reindex_task, which drains the reindex and delete coalescing buffers and enqueues bulk thread tasks. Longer values cut Celery/OpenSearch load at the cost of search-result staleness. |
Optional |
SEARCH_FLUSH_BATCH_SIZE |
1000 |
Maximum number of thread / message IDs handed to a single bulk_*_task call. This is the unit of parallelism, retry granularity and worker occupation for catch-up flows. Lower means more, shorter tasks (better parallelism, cheaper retries on failure); higher means fewer, longer tasks (less broker chatter but worse failure isolation). |
Optional |
SEARCH_FLUSH_MAX_BATCHES |
10 |
Maximum number of bulk_*_task calls a single Beat tick is allowed to enqueue, shared across the three handoffs (reindex / thread-delete / message-delete). Bounds catch-up bursts so a huge backlog is spread across several ticks rather than flooding the broker in one go. Effective per-tick capacity is roughly SEARCH_FLUSH_BATCH_SIZE × SEARCH_FLUSH_MAX_BATCHES IDs. |
Optional |
Mail Processing Configuration
MTA Settings
| Variable |
Default |
Description |
Required |
MTA_OUT_MODE |
direct |
Outbound MTA mode ('direct' or 'relay') |
Required |
MTA_OUT_RELAY_HOST |
mta-out:587 |
Outbound SMTP server host for relay mode |
Required |
MTA_OUT_RELAY_USERNAME |
user |
Outbound SMTP username for relay mode |
Optional |
MTA_OUT_RELAY_PASSWORD |
pass |
Outbound SMTP password for relay mode |
Optional |
MTA_OUT_DIRECT_PROXIES |
[] |
List of SOCKS proxy URLs (randomly chosen when non-empty; used in direct mode) |
Optional |
MTA_OUT_DIRECT_PORT |
25 |
TCP port for direct mode on remote MX servers |
Optional |
MTA_OUT_SMTP_TLS_SECURITY_LEVEL |
may |
SMTP TLS security level ("none", "may") |
Optional |
MDA_API_SECRET |
my-shared-secret-mda |
Shared secret for MDA API |
Required |
MDA_API_BASE_URL |
http://backend-dev:8000/api/v1.0/ |
Base URL for MDA API |
Dev |
Email Domain Configuration
| Variable |
Default |
Description |
Required |
MESSAGES_TESTDOMAIN |
example.local |
Test domain for development |
Dev |
MESSAGES_TESTDOMAIN_MAPPING_BASEDOMAIN |
example.com |
Base domain mapping |
Dev |
MESSAGES_ACCEPT_ALL_EMAILS |
False |
Accept emails to any domain |
Optional |
DKIM Configuration
| Variable |
Default |
Description |
Required |
MESSAGES_DKIM_SELECTOR |
default |
DKIM selector |
Optional |
MESSAGES_DKIM_DOMAINS |
[] |
List of domains for DKIM signing |
Optional |
MESSAGES_DKIM_PRIVATE_KEY_B64 |
None |
Base64 encoded DKIM private key |
Optional |
MESSAGES_DKIM_PRIVATE_KEY_FILE |
None |
Path to DKIM private key file |
Optional |
Storage Configuration
S3-Compatible Storage
| Variable |
Default |
Description |
Required |
AWS_S3_ENDPOINT_URL |
http://objectstorage:9000 |
S3 endpoint URL |
Optional |
AWS_S3_ACCESS_KEY_ID |
messages |
S3 access key |
Optional |
AWS_S3_SECRET_ACCESS_KEY |
password |
S3 secret key |
Optional |
AWS_S3_REGION_NAME |
None |
S3 region |
Optional |
AWS_STORAGE_BUCKET_NAME |
st-messages-media-storage |
S3 bucket name |
Optional |
AWS_S3_UPLOAD_POLICY_EXPIRATION |
86400 |
Upload policy expiration (24h) |
Optional |
MEDIA_BASE_URL |
http://localhost:8902 |
Base URL for media files |
Optional |
ITEM_FILE_MAX_SIZE |
5368709120 |
Max file size (5GB) |
Optional |
Message Imports Storage
| Variable |
Default |
Description |
Required |
STORAGE_MESSAGE_IMPORTS_ENDPOINT_URL |
http://objectstorage:9000 |
S3 endpoint URL |
Required |
STORAGE_MESSAGE_IMPORTS_BUCKET_NAME |
msg-imports |
S3 bucket name |
Required |
STORAGE_MESSAGE_IMPORTS_ACCESS_KEY |
st-messages |
S3 access key |
Required |
STORAGE_MESSAGE_IMPORTS_SECRET_KEY |
password |
S3 secret key |
Required |
STORAGE_MESSAGE_IMPORTS_REGION_NAME |
None |
S3 region |
Optional |
STORAGE_MESSAGE_IMPORTS_EXPIRE_POLICY |
3600 |
Upload policy expiration (1h) |
Optional |
Static Files
| Variable |
Default |
Description |
Required |
STORAGES_STATICFILES_BACKEND |
django.contrib.staticfiles.storage.StaticFilesStorage |
Static files storage backend |
Optional |
Authentication & Authorization
OIDC Configuration
| Variable |
Default |
Description |
Required |
OIDC_CREATE_USER |
False |
Automatically create users from OIDC |
Optional |
OIDC_RP_CLIENT_ID |
messages |
OIDC client ID |
Required |
OIDC_RP_CLIENT_SECRET |
ThisIsAnExampleKeyForDevPurposeOnly |
OIDC client secret |
Required |
OIDC_RP_SIGN_ALGO |
RS256 |
OIDC signing algorithm |
Optional |
OIDC_RP_SCOPES |
openid email |
OIDC scopes |
Optional |
OIDC_OP_JWKS_ENDPOINT |
http://keycloak:8000/realms/messages/protocol/openid-connect/certs |
OIDC JWKS endpoint |
Required |
OIDC_OP_AUTHORIZATION_ENDPOINT |
http://localhost:8902/realms/messages/protocol/openid-connect/auth |
OIDC authorization endpoint |
Required |
OIDC_OP_TOKEN_ENDPOINT |
http://keycloak:8000/realms/messages/protocol/openid-connect/token |
OIDC token endpoint |
Required |
OIDC_OP_USER_ENDPOINT |
http://keycloak:8000/realms/messages/protocol/openid-connect/userinfo |
OIDC user info endpoint |
Required |
OIDC_OP_LOGOUT_ENDPOINT |
None |
OIDC logout endpoint |
Optional |
OIDC_USERINFO_ESSENTIAL_CLAIMS |
[] |
Essential OIDC claims |
Optional |
OIDC_USERINFO_FULLNAME_FIELDS |
["first_name", "last_name"] |
Fields to use for full name |
Optional |
OIDC_STORE_ACCESS_TOKEN |
False |
Store access token |
Optional |
OIDC_STORE_REFRESH_TOKEN |
False |
Store refresh token |
Optional |
OIDC_STORE_REFRESH_TOKEN_KEY |
None |
Refresh token encryption key (Must be a valid Fernet key) |
Optional |
OIDC Advanced Settings
| Variable |
Default |
Description |
Required |
OIDC_USE_NONCE |
True |
Use nonce in OIDC flow |
Optional |
OIDC_REDIRECT_REQUIRE_HTTPS |
False |
Require HTTPS for redirects |
Optional |
OIDC_REDIRECT_ALLOWED_HOSTS |
["http://localhost:8902", "http://localhost:8900"] |
Allowed redirect hosts |
Optional |
OIDC_STORE_ID_TOKEN |
True |
Store ID token |
Optional |
OIDC_FALLBACK_TO_EMAIL_FOR_IDENTIFICATION |
True |
Use email as fallback identifier |
Optional |
OIDC_ALLOW_DUPLICATE_EMAILS |
False |
Allow duplicate emails (⚠️ Security risk) |
Optional |
OIDC_AUTH_REQUEST_EXTRA_PARAMS |
{"acr_values": "eidas1"} |
Extra parameters for auth requests |
Optional |
User Mapping (⚠️ DEPRECATED)
Those settings are deprecated and will be removed in the future.
| Variable |
Default |
Description |
Required |
⚠️ Deprecated |
USER_OIDC_ESSENTIAL_CLAIMS |
[] |
Essential OIDC claims |
Optional |
Renamed to OIDC_USERINFO_ESSENTIAL_CLAIMS |
USER_OIDC_FIELDS_TO_FULLNAME |
["first_name", "last_name"] |
Fields for full name |
Optional |
Renamed to OIDC_USERINFO_FULLNAME_FIELDS |
USER_OIDC_FIELD_TO_SHORTNAME |
first_name |
Field for short name |
Optional |
Unused, will be removed in the future |
Authentication URLs
| Variable |
Default |
Description |
Required |
LOGIN_REDIRECT_URL |
http://localhost:8900 |
Post-login redirect URL |
Optional |
LOGIN_REDIRECT_URL_FAILURE |
http://localhost:8900 |
Login failure redirect URL |
Optional |
LOGOUT_REDIRECT_URL |
http://localhost:8900 |
Post-logout redirect URL |
Optional |
ALLOW_LOGOUT_GET_METHOD |
True |
Allow GET method for logout |
Optional |
Security & CORS
| Variable |
Default |
Description |
Required |
CORS_ALLOW_ALL_ORIGINS |
True |
Allow all CORS origins |
Optional |
CORS_ALLOWED_ORIGINS |
[] |
Specific allowed CORS origins |
Optional |
CORS_ALLOWED_ORIGIN_REGEXES |
[] |
Regex patterns for allowed origins |
Optional |
CSRF_TRUSTED_ORIGINS |
["http://localhost:8900", "http://localhost:8901"] |
Trusted origins for CSRF |
Optional |
SERVER_TO_SERVER_API_TOKENS |
[] |
API tokens for server-to-server auth |
Optional |
Monitoring & Observability
Sentry
| Variable |
Default |
Description |
Required |
SENTRY_DSN |
None |
Sentry DSN for error tracking |
Optional |
NEXT_PUBLIC_SENTRY_DSN |
None |
Sentry DSN for error tracking |
Optional |
NEXT_PUBLIC_SENTRY_ENVIRONMENT |
None |
Sentry environment for error tracking |
Optional ('production', 'development', 'staging') |
Logging
| Variable |
Default |
Description |
Required |
LOGGING_LEVEL_LOGGERS_ROOT |
INFO |
Root logger level |
Optional |
LOGGING_LEVEL_LOGGERS_APP |
INFO |
Application logger level |
Optional |
LOGGING_LEVEL_HANDLERS_CONSOLE |
INFO |
Console handler level |
Optional |
Prometheus
| Variable |
Default |
Description |
Required |
ENABLE_PROMETHEUS |
False |
Enable Prometheus monitoring |
Optional |
PROMETHEUS_API_KEY |
None |
Bearer token required to access metrics. If unset, the endpoint is public. Set this in production. |
Optional |
OpenAPI Schema
| Variable |
Default |
Description |
Required |
SPECTACULAR_SETTINGS_ENABLE_DJANGO_DEPLOY_CHECK |
False |
Enable deploy check in OpenAPI |
Optional |
Frontend Configuration
| Variable |
Default |
Description |
Required |
NEXT_PUBLIC_API_ORIGIN |
http://localhost:8901 |
Frontend API origin |
Dev |
NEXT_PUBLIC_LANGUAGES |
[["en-US","English"],["fr-FR","Français"],["nl-NL","Nederlands"]] |
Languages available for frontend |
Optional |
NEXT_PUBLIC_DEFAULT_LANGUAGE |
en-US |
Default language for frontend |
Optional |
NEXT_PUBLIC_FORCED_DEFAULT_LANGUAGE |
false |
When true, the default language fallback is NEXT_PUBLIC_DEFAULT_LANGUAGE instead of the browser language. |
Optional |
NEXT_PUBLIC_THEME_CONFIG |
{theme: "white-label"} |
Theme configuration for frontend |
Optional |
NEXT_PUBLIC_FEEDBACK_WIDGET_API_URL |
|
Feedback widget API URL |
Optional |
NEXT_PUBLIC_FEEDBACK_WIDGET_PATH |
|
Feedback widget path |
Optional |
NEXT_PUBLIC_FEEDBACK_WIDGET_CHANNEL |
|
Feedback widget channel used by the in-app survey button (authenticated header) |
Optional |
NEXT_PUBLIC_FEEDBACK_WIDGET_HOME_CHANNEL |
|
Feedback widget channel used on the unauthenticated home page. Falls back to NEXT_PUBLIC_FEEDBACK_WIDGET_CHANNEL when unset |
Optional |
NEXT_PUBLIC_HELP_CENTER_URL |
|
Help center URL |
Optional |
Development Tools
Crowdin (Translations)
| Variable |
Default |
Description |
Required |
CROWDIN_PERSONAL_TOKEN |
Your-Personal-Token |
Crowdin API token |
Dev |
CROWDIN_PROJECT_ID |
Your-Project-Id |
Crowdin project ID |
Dev |
CROWDIN_BASE_PATH |
/app/src |
Base path for translations |
Dev |
Application Settings
Common Feature Flags
Kill-switches for opt-out features. Flip to False to disable the
corresponding API action and hide the related frontend entry points,
without redeploying the frontend (the flag is pulled from
GET /api/v1.0/config/).
| Variable |
Default |
Description |
Required |
FEATURE_IMPORT_MESSAGES |
True |
Enables message import (IMAP, PST, MBOX, etc.). When False, mailbox admins lose the CAN_IMPORT_MESSAGES ability. |
Optional |
FEATURE_MAILBOX_ADMIN_CHANNELS |
`` |
Comma-separated list of channel types enabled for mailbox admin (e.g., widget,api_key). Empty list disables all channel types. |
Optional |
FEATURE_MAILDOMAIN_CREATE |
True |
Allows superusers to create new mail domains via the API. When False, the create action returns 403. |
Optional |
FEATURE_MAILDOMAIN_MANAGE_ACCESSES |
True |
Allows managing mail domain accesses (create/delete). When False, those actions return 403. |
Optional |
FEATURE_MESSAGE_TEMPLATES |
True |
Enables the "message templates" feature. When False, mailbox admins lose the CAN_MANAGE_MESSAGE_TEMPLATES ability and the related UI is hidden. |
Optional |
FEATURE_THREAD_SPLIT |
True |
Enables "split thread" feature. When False, the split API action returns 404 and the frontend hides the menu entry. |
Optional |
Business Logic
| Variable |
Default |
Description |
Required |
TRASHBIN_CUTOFF_DAYS |
30 |
Days before permanent deletion |
Optional |
INVITATION_VALIDITY_DURATION |
604800 |
Invitation validity (7 days) |
Optional |
MESSAGES_MANUAL_RETRY_MAX_AGE |
604800 |
Maximum age in seconds for a message to be eligible for manual retry of failed deliveries (7 days) |
Optional |
MAX_INCOMING_EMAIL_SIZE |
10485760 |
Maximum size in bytes for incoming email (including attachments and body) (10MB) |
Optional |
MAX_OUTGOING_ATTACHMENT_SIZE |
20971520 |
Maximum size in bytes for outgoing email attachments (20MB) |
Optional |
MAX_OUTGOING_BODY_SIZE |
5242880 |
Maximum size in bytes for outgoing email body (text + HTML) (5MB) |
Optional |
MAX_TEMPLATE_IMAGE_SIZE |
2097152 |
Maximum size in bytes for images embedded in templates and signatures (2MB) |
Optional |
MAX_RECIPIENTS_PER_MESSAGE |
500 |
Maximum number of recipients per message (to + cc + bcc) |
Optional |
MAX_THREAD_EVENT_EDIT_DELAY |
3600 |
Time window in seconds during which a ThreadEvent (internal comment) can still be edited or deleted after creation. Set to 0 to disable the restriction. |
Optional |
Model custom attributes schema
Note: Custom attributes are stored in a JSONField (Take a look at User and MailDomain models).
| Variable |
Default |
Description |
Required |
SCHEMA_CUSTOM_ATTRIBUTES_USER |
{} |
JSONSchema definition of the User custom attributes |
Optional |
SCHEMA_CUSTOM_ATTRIBUTES_MAILDOMAIN |
{} |
JSONSchema definition of the MailDomain custom attributes |
Optional |
Internationalization
| Variable |
Default |
Description |
Required |
LANGUAGE_CODE |
en-us |
Default backend language code |
Optional |
AI
| Variable |
Default |
Description |
Required |
AI_BASE_URL |
None |
Default URL to access AI API endpoint (Albert API) |
Optional |
AI_API_KEY |
None |
API Key used for AI features |
Optional |
AI_MODEL |
None |
Default model used for AI features |
Optional |
FEATURE_AI_SUMMARY |
False |
Default enabled mode for summary AI features |
Required |
FEATURE_AI_AUTOLABELS |
False |
Default enabled mode for label AI features |
Required |
Throttling
Outbound message throttling limits the number of external recipients (recipients whose domain is not managed by this instance) that can be sent from a mailbox or maildomain within a time period, using simple fixed time windows.
| Variable |
Default |
Description |
Required |
THROTTLE_MAILBOX_OUTBOUND_EXTERNAL_RECIPIENTS |
None |
Rate limit per mailbox. Format: count/period where period is minute, hour, or day. Example: 1000/day limits each mailbox to 1000 external recipients per day. |
Optional |
THROTTLE_MAILDOMAIN_OUTBOUND_EXTERNAL_RECIPIENTS |
None |
Rate limit per maildomain. Format: count/period. Example: 10000/day limits each domain to 10000 external recipients per day. |
Optional |
THROTTLE_AUTOREPLY_PER_SENDER |
1/day |
Rate limit for autoreplies per sender per mailbox. Format: count/period. Example: 1/day limits each sender to 1 autoreply per day per mailbox. |
Optional |
Image Proxy
Note: By default IMAGE_PROXY_MAX_SIZE is set to 5MB. We do not encourage to increase this value as
it can lead to memory exhaustion, increase at your own risk.
| Variable |
Default |
Description |
Required |
IMAGE_PROXY_ENABLED |
False |
Whether external images should be proxied |
Optional |
IMAGE_PROXY_MAX_SIZE |
5242880 (5MB) |
Maximum size in bytes for external images |
Optional |
IMAGE_PROXY_CACHE_TTL |
2592000 (30 days) |
Cache TTL in seconds for external images |
Optional |
Frontend
| Variable |
Default |
Description |
Required |
FRONTEND_THEME |
white-label |
Theme for the frontend |
Optional |
FRONTEND_SILENT_LOGIN_ENABLED |
False |
Whether silent login is enabled |
Optional |
Third-party Services
Drive
| Variable |
Default |
Description |
Required |
DRIVE_BASE_URL |
None |
Base URL to access Drive endpoints |
Optional |
DRIVE_APP_NAME |
Drive |
Name of the Drive application used in the frontend |
Optional |
Legend
- Required: Must be set for the application to function
- Dev: Required for development/testing environments
- Optional: Has sensible defaults, can be customized
Environment Files
The application uses environment files located in env.d/development/ for different services:
backend.defaults - Main Django application settings
common.defaults - Shared settings across services
frontend.defaults - Frontend configuration
postgresql.defaults - PostgreSQL database configuration
keycloak.defaults - Keycloak configuration
mta-in.defaults - Inbound mail server settings
mta-out.defaults - Outbound mail server settings
crowdin.defaults - Translation service configuration
Local Overrides
The make bootstrap command creates empty .local files for each service with a comment header:
These files are gitignored and allow for local development customizations without affecting the repository.
Security Notes
⚠️ Important Security Considerations:
- Never commit actual secrets - Use
.local files only
- OIDC_ALLOW_DUPLICATE_EMAILS - Should remain
False in production
- CORS_ALLOW_ALL_ORIGINS - Should be
False in production
- DJANGO_SECRET_KEY - Must be unique and secret in production
- Database passwords - Use strong, unique passwords
- API tokens - Rotate regularly and keep secure
Production Deployment
For production deployments, ensure:
- All Required variables are properly configured
- Secrets are managed through secure secret management systems
- HTTPS is enforced for all external communications
- Database connections use SSL/TLS
- File storage uses appropriate access controls