{"record":{"id":"7741330a3df692ef","repo":"django/django","slug":"mailers-alias-r-options-must-define-host","errorCode":null,"errorMessage":"MAILERS[{alias!r}]: OPTIONS must define 'host'.","messagePattern":"MAILERS\\[(.+?)\\]: OPTIONS must define 'host'\\.","errorType":"exception","errorClass":"InvalidMailer","httpStatus":null,"severity":"error","filePath":"django/core/mail/backends/smtp.py","lineNumber":86,"sourceCode":"            )\n            if self.use_ssl and self.use_tls:\n                raise ValueError(\n                    \"EMAIL_USE_TLS/EMAIL_USE_SSL are mutually exclusive, so \"\n                    \"only set one of those settings to True.\"\n                )\n            return\n\n        self.host = host\n        self.port = port\n        self.username = username\n        self.password = password\n        self.use_tls = use_tls if use_tls is not None else False\n        self.use_ssl = use_ssl if use_ssl is not None else False\n        self.timeout = timeout\n        self.ssl_keyfile = ssl_keyfile\n        self.ssl_certfile = ssl_certfile\n        if self.host is None:\n            raise InvalidMailer(\"OPTIONS must define 'host'.\", alias=self.alias)\n        if self.use_ssl and self.use_tls:\n            raise InvalidMailer(\n                \"The 'use_ssl' and 'use_tls' OPTIONS are incompatible. \"\n                \"Set at most one of them to True.\",\n                alias=self.alias,\n            )\n        if self.port is None:\n            if self.use_ssl:\n                self.port = 465\n            elif self.use_tls:\n                self.port = 587\n            else:\n                self.port = 25\n\n    @property\n    def connection_class(self):\n        return smtplib.SMTP_SSL if self.use_ssl else smtplib.SMTP\n","sourceCodeStart":68,"sourceCodeEnd":104,"githubUrl":"https://github.com/django/django/blob/ae25a40be07e8a749edf526df37c93e59d4a22c9/django/core/mail/backends/smtp.py#L68-L104","documentation":"Raised by the MAILERS-based SMTP email backend (alias is not None) when host is None after construction. It is an InvalidMailer error, message prefixed with MAILERS[<alias>]:. Unlike the deprecated path which falls back to settings.EMAIL_HOST, the MAILERS path requires an explicit 'host' in OPTIONS because the new system intentionally has no implicit default host. The check is at smtp.py:85-86.","triggerScenarios":"Defining a MAILERS alias with BACKEND 'django.core.mail.backends.smtp.EmailBackend' whose OPTIONS omits 'host', then accessing mailers[<alias>] or sending with using=<alias>.","commonSituations":"Migrating from EMAIL_HOST to MAILERS and forgetting to copy host into OPTIONS; aliasing a copy of the default config and stripping the host; typo 'Host' vs 'host' (the option is lowercase).","solutions":["Add 'host' to the alias OPTIONS, e.g. OPTIONS: {'host': 'smtp.example.com', 'port': 587}.","Validate at startup: `assert 'host' in MAILERS['transactional']['OPTIONS'], 'host required'`.","Keep port and credentials consistent in the same OPTIONS dict."],"exampleFix":"# before\nMAILERS = {\n    \"default\": {\n        \"BACKEND\": \"django.core.mail.backends.smtp.EmailBackend\",\n        \"OPTIONS\": {\"port\": 587, \"username\": \"u\", \"password\": \"p\"},\n    },\n}\n\n# after\nMAILERS = {\n    \"default\": {\n        \"BACKEND\": \"django.core.mail.backends.smtp.EmailBackend\",\n        \"OPTIONS\": {\n            \"host\": \"smtp.example.com\",\n            \"port\": 587,\n            \"username\": \"u\",\n            \"password\": \"p\",\n            \"use_tls\": True,\n        },\n    },\n}","handlingStrategy":"validation","validationCode":"from django.conf import settings\n\ndef validate_smtp_mailers_have_host():\n    for alias, cfg in getattr(settings, \"MAILERS\", {}).items():\n        if cfg.get(\"BACKEND\") == \"django.core.mail.backends.smtp.EmailBackend\":\n            if not cfg.get(\"OPTIONS\", {}).get(\"host\"):\n                raise ImproperlyConfigured(\n                    f\"MAILERS[{alias!r}] SMTP backend requires OPTIONS['host']\"\n                )","typeGuard":"def is_valid_smtp_mailer(cfg: dict) -> bool:\n    return (\n        cfg.get(\"BACKEND\") == \"django.core.mail.backends.smtp.EmailBackend\"\n        and isinstance(cfg.get(\"OPTIONS\"), dict)\n        and isinstance(cfg[\"OPTIONS\"].get(\"host\"), str)\n        and bool(cfg[\"OPTIONS\"][\"host\"])\n    )","tryCatchPattern":"from django.core.mail import InvalidMailer\nfrom django.core import mail\ntry:\n    mail.mailers[\"default\"]\nexcept InvalidMailer as e:\n    if \"OPTIONS must define 'host'\" in str(e):\n        raise SystemExit(\"Add OPTIONS['host'] to the SMTP MAILERS alias.\")\n    raise","preventionTips":["Always include 'host' in every SMTP alias OPTIONS.","Centralize mailer construction in a helper that asserts host is present.","Add a startup check that all SMTP aliases define host, port, and TLS mode."],"tags":["email","smtp","mailers","configuration","django"],"analyzedSha":"ae25a40be07e8a749edf526df37c93e59d4a22c9","analyzedAt":"2026-08-06T21:46:51.801Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}