{"record":{"id":"2edf131496c443b3","repo":"makeplane/plane","slug":"5025","errorCode":"5025","errorMessage":"SMTP_NOT_CONFIGURED","messagePattern":"SMTP_NOT_CONFIGURED","errorType":"exception","errorClass":"AuthenticationException","httpStatus":null,"severity":"error","filePath":"apps/api/plane/authentication/provider/credentials/magic_code.py","lineNumber":58,"sourceCode":"    )\n\n    @staticmethod\n    def _verify_attempts_key(token_key):\n        return f\"{token_key}:verify_attempts\"\n\n    def __init__(self, request, key, code=None, callback=None):\n        (EMAIL_HOST, ENABLE_MAGIC_LINK_LOGIN) = get_configuration_value(\n            [\n                {\"key\": \"EMAIL_HOST\", \"default\": os.environ.get(\"EMAIL_HOST\")},\n                {\n                    \"key\": \"ENABLE_MAGIC_LINK_LOGIN\",\n                    \"default\": os.environ.get(\"ENABLE_MAGIC_LINK_LOGIN\", \"1\"),\n                },\n            ]\n        )\n\n        if not (EMAIL_HOST):\n            raise AuthenticationException(\n                error_code=AUTHENTICATION_ERROR_CODES[\"SMTP_NOT_CONFIGURED\"],\n                error_message=\"SMTP_NOT_CONFIGURED\",\n                payload={\"email\": str(key)},\n            )\n\n        if ENABLE_MAGIC_LINK_LOGIN == \"0\":\n            raise AuthenticationException(\n                error_code=AUTHENTICATION_ERROR_CODES[\"MAGIC_LINK_LOGIN_DISABLED\"],\n                error_message=\"MAGIC_LINK_LOGIN_DISABLED\",\n                payload={\"email\": str(key)},\n            )\n\n        super().__init__(request=request, provider=self.provider, callback=callback)\n        self.key = key\n        self.code = code\n\n    def initiate(self):\n        ## Generate a random token","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/makeplane/plane/blob/1c8a60f858d8472aa56e29994ec1c7926da2c6ce/apps/api/plane/authentication/provider/credentials/magic_code.py#L40-L76","documentation":"Raised in MagicCodeProvider.__init__ (magic_code.py:58) when EMAIL_HOST is falsy. EMAIL_HOST is read from instance config with an env fallback; an empty value means no SMTP server is configured, so magic-code emails cannot be delivered. Code 5025, payload {email}.","triggerScenarios":"Constructing the MagicCodeProvider (initiate or verify) resolves EMAIL_HOST via get_configuration_value. If it is empty/None, AuthenticationException is raised before any code is generated or sent. Hit by calling the magic-code request or verify endpoint on an instance without SMTP.","commonSituations":"Fresh/self-hosted deploy without EMAIL_HOST set; SMTP migrated away and config not updated; instance intended for SSO-only but the UI still exposes magic-code.","solutions":["Set EMAIL_HOST (and related SMTP creds: EMAIL_HOST_USER, EMAIL_HOST_PASSWORD, EMAIL_PORT, EMAIL_USE_TLS) in instance config/env.","If SMTP is intentionally unavailable, hide/disable the magic-code UI and guide users to the configured auth methods.","Restart/reload the API after changing SMTP config so get_configuration_value picks up the new value."],"exampleFix":"# before: EMAIL_HOST unset -> magic-code init -> 5025\n# EMAIL_HOST=smtp.example.com\n# EMAIL_PORT=587\n# EMAIL_USE_TLS=1\n# after: SMTP configured, magic-code tokens are emailed","handlingStrategy":"validation","validationCode":"from plane.license.utils.instance_value import get_configuration_value\nimport os\n\ndef smtp_configured() -> bool:\n    (host,) = get_configuration_value([{'key': 'EMAIL_HOST', 'default': os.environ.get('EMAIL_HOST')}])\n    return bool(host)","typeGuard":null,"tryCatchPattern":"try:\n    MagicCodeProvider(request, key=email)\nexcept AuthenticationException as e:\n    if e.error_code == 5025:\n        hide_magic_code_ui(); offer_alternative_auth()\n    else:\n        raise","preventionTips":["Only expose magic-code in the UI when EMAIL_HOST is set.","Validate the full SMTP config (host, port, user, password, TLS) at deploy time."],"tags":["authentication","magic-code","smtp","configuration","email","env"],"backgroundTag":null,"analyzedSha":"1c8a60f858d8472aa56e29994ec1c7926da2c6ce","analyzedAt":"2026-08-12T14:44:31.636Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}