Budibase/budibase · error · Error

IMAP host is blocked or could not be resolved safely

Error message

IMAP host is blocked or could not be resolved safely

What it means

getClient checks the configured IMAP host against an SSRF blacklist before connecting. If the host is blacklisted (or cannot be safely resolved, e.g. it maps to internal/private addresses), the connection is refused with this error to protect the server from SSRF attacks.

Source

Thrown at packages/server/src/automations/email/utils/getClient.ts:106

  }

  if (!inputs.password) {
    throw new Error("IMAP password is required")
  }

  return {
    user: inputs.username,
    pass: inputs.password,
  }
}

export const getClient = async (inputs: EmailTriggerInputs) => {
  if (!inputs) {
    throw new Error("Email trigger inputs are required")
  }

  if (await blacklist.isBlacklisted(inputs.host)) {
    throw new Error("IMAP host is blocked or could not be resolved safely")
  }

  const client = new ImapFlow({
    host: inputs.host,
    port: inputs.port,
    secure: inputs.secure,
    auth: await getAuthConfig(inputs),
    // imap flow has its own pino instance enabled by default and is very very chatty!
    logger: false,
  })

  return client
}

View on GitHub (pinned to a81a902e9a)

Solutions

  1. Use a public, routable IMAP hostname (e.g. imap.example.com) instead of an internal/private address
  2. Verify DNS resolution of the host from the server environment
  3. Check the blacklist implementation to confirm whether the host is intentionally blocked and request an allowlist if legitimate
  4. Correct typos in the host field of the trigger config

Example fix

// before
{ "host": "192.168.1.10" } // private IP blocked by SSRF guard
// after
{ "host": "imap.example.com" }
Defensive patterns

Strategy: validation

Validate before calling

import { isIP } from "net"
const host = inputs.host
if (!host || host === "localhost" || /^(10\.|127\.|192\.168\.|169\.254\.|172\.(1[6-9]|2\d|3[01])\.)/.test(host)) {
  throw new Error("Use a public IMAP hostname")
}

Type guard

function isPublicHost(host: string): boolean {
  return typeof host === "string" && host.length > 0 &&
    !/^localhost$/i.test(host) &&
    !/^(10\.|127\.|192\.168\.|169\.254\.|172\.(1[6-9]|2\d|3[01])\.)/.test(host)
}

Try / catch

try {
  const client = await getClient(inputs)
} catch (err) {
  if (err.message.includes("blocked or could not be resolved safely")) {
    // surface a config error to the user: host is private/unresolvable
  }
  throw err
}

Prevention

When it happens

Trigger: inputs.host resolves to a blacklisted entry (internal IPs, localhost, metadata endpoints) or the blacklist resolver cannot safely resolve the hostname at automation runtime.

Common situations: Pointing the email trigger at an internal mail server on a deployment with SSRF protections; hostnames that fail DNS resolution; typo'd host values resolving to private ranges; hardened environments blocking private network egress.

Related errors


AI-assisted analysis of Budibase/budibase@a81a902e9a (2026-08-29). Data as JSON: /api/errors/00ac4ffee5883288. Report an issue: GitHub.