getredash/redash · error

Bad email address.

Error message

Bad email address.

What it means

Raised by require_allowed_email in redash/handlers/users.py when the domain part of the email (normalized: lowercased, trailing dot stripped) is in the internal blacklist or in the settings.BLOCKED_DOMAINS configuration. This is a signup/invite spam guard.

Source

Thrown at redash/handlers/users.py:64

def invite_user(org, inviter, user, send_email=True):
    d = user.to_dict()

    invite_url = invite_link_for_user(user)
    if settings.email_server_is_configured() and send_email:
        send_invite_email(inviter, user, invite_url, org)
    else:
        d["invite_link"] = invite_url

    return d


def require_allowed_email(email):
    # `example.com` and `example.com.` are equal - last dot stands for DNS root but usually is omitted
    _, domain = email.lower().rstrip(".").split("@", 1)

    if domain in blacklist or domain in settings.BLOCKED_DOMAINS:
        abort(400, message="Bad email address.")


class UserListResource(BaseResource):
    decorators = BaseResource.decorators + [limiter.limit("200/day;50/hour", methods=["POST"])]

    def get_users(self, disabled, pending, search_term):
        if disabled:
            users = models.User.all_disabled(self.current_org)
        else:
            users = models.User.all(self.current_org)

        if pending is not None:
            users = models.User.pending(users, pending)

        if search_term:
            users = models.User.search(users, search_term)
            self.record_event(
                {

View on GitHub (pinned to ca79fe988d)

Solutions

  1. Use an email at an allowed (non-blocked) domain.
  2. If you administer the instance, review/remove the domain from settings.BLOCKED_DOMAINS.
  3. Normalize the address (lowercase, no trailing dot) before checking against your own list.

Example fix

# before
client.post('/api/users', json={'name': 'X', 'email': 'user@mailinator.com'})

# after
client.post('/api/users', json={'name': 'X', 'email': 'user@corp.com'})
Defensive patterns

Strategy: validation

Validate before calling

domain = email.lower().rstrip('.').split('@', 1)[1]
if domain in blocked_domains:
    raise ValueError('email domain blocked')

Type guard

def is_allowed_email(email: str, blocked: set) -> bool:
    try:
        _, domain = email.lower().rstrip('.').split('@', 1)
    except ValueError:
        return False
    return domain not in blocked

Prevention

When it happens

Trigger: Inviting a user (POST /api/users, or the invite flow) with an email at a blocked domain, e.g. mailinator.com or any domain listed in REDASH_BLOCKED_DOMAINS.

Common situations: Disposable-email blocking configured via env var; corporate installs blocking personal-mail domains; testers using throwaway addresses that land on the default blacklist.

Related errors


AI-assisted analysis of getredash/redash@ca79fe988d (2026-08-28). Data as JSON: /api/errors/14f2a6f4dfde50dc. Report an issue: GitHub.