makeplane/plane · error · AuthenticationException

5025

5025

Error message

SMTP_NOT_CONFIGURED

What it means

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}.

Source

Thrown at apps/api/plane/authentication/provider/credentials/magic_code.py:58

    )

    @staticmethod
    def _verify_attempts_key(token_key):
        return f"{token_key}:verify_attempts"

    def __init__(self, request, key, code=None, callback=None):
        (EMAIL_HOST, ENABLE_MAGIC_LINK_LOGIN) = get_configuration_value(
            [
                {"key": "EMAIL_HOST", "default": os.environ.get("EMAIL_HOST")},
                {
                    "key": "ENABLE_MAGIC_LINK_LOGIN",
                    "default": os.environ.get("ENABLE_MAGIC_LINK_LOGIN", "1"),
                },
            ]
        )

        if not (EMAIL_HOST):
            raise AuthenticationException(
                error_code=AUTHENTICATION_ERROR_CODES["SMTP_NOT_CONFIGURED"],
                error_message="SMTP_NOT_CONFIGURED",
                payload={"email": str(key)},
            )

        if ENABLE_MAGIC_LINK_LOGIN == "0":
            raise AuthenticationException(
                error_code=AUTHENTICATION_ERROR_CODES["MAGIC_LINK_LOGIN_DISABLED"],
                error_message="MAGIC_LINK_LOGIN_DISABLED",
                payload={"email": str(key)},
            )

        super().__init__(request=request, provider=self.provider, callback=callback)
        self.key = key
        self.code = code

    def initiate(self):
        ## Generate a random token

View on GitHub (pinned to 1c8a60f858)

Solutions

  1. Set EMAIL_HOST (and related SMTP creds: EMAIL_HOST_USER, EMAIL_HOST_PASSWORD, EMAIL_PORT, EMAIL_USE_TLS) in instance config/env.
  2. If SMTP is intentionally unavailable, hide/disable the magic-code UI and guide users to the configured auth methods.
  3. Restart/reload the API after changing SMTP config so get_configuration_value picks up the new value.

Example fix

# before: EMAIL_HOST unset -> magic-code init -> 5025
# EMAIL_HOST=smtp.example.com
# EMAIL_PORT=587
# EMAIL_USE_TLS=1
# after: SMTP configured, magic-code tokens are emailed
Defensive patterns

Strategy: validation

Validate before calling

from plane.license.utils.instance_value import get_configuration_value
import os

def smtp_configured() -> bool:
    (host,) = get_configuration_value([{'key': 'EMAIL_HOST', 'default': os.environ.get('EMAIL_HOST')}])
    return bool(host)

Try / catch

try:
    MagicCodeProvider(request, key=email)
except AuthenticationException as e:
    if e.error_code == 5025:
        hide_magic_code_ui(); offer_alternative_auth()
    else:
        raise

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of makeplane/plane@1c8a60f858 (2026-08-12). Data as JSON: /api/errors/2edf131496c443b3. Report an issue: GitHub.