postalserver/postal · warning · Postal::MessageInspectors::Rspamd::Error

Error when scanning with rspamd (#{e.class})

Error message

Error when scanning with rspamd (#{e.class})

What it means

Postal's rspamd message inspector POSTs messages to rspamd's /checkv2 with 10s open/read timeouts; any StandardError from that request (ECONNREFUSED, timeout, DNS failure, TLS error) is first logged ('Error talking to rspamd: ...') and then re-raised as Rspamd::Error with the original class name interpolated. inspect_message catches Error and records a SpamCheck named ERROR, so the message still flows but spam inspection is degraded for it.

Source

Thrown at lib/postal/message_inspectors/rspamd.rb:63

        request["Queue-Id"] = message.token

        if scope == :outgoing
          request["User"] = ""
          # We don't actually know the IP but an empty input here will
          # still trigger rspamd to treat this as an outbound email
          # and disable certain checks.
          # https://rspamd.com/doc/tutorials/scanning_outbound.html
          request["Ip"] = ""
        end

        response = nil
        begin
          response = http.request(request)
        rescue StandardError => e
          logger.error "Error talking to rspamd: #{e.class} (#{e.message})"
          logger.error e.backtrace[0, 5]

          raise Error, "Error when scanning with rspamd (#{e.class})"
        end

        unless response.is_a?(Net::HTTPOK)
          logger.info "Got #{response.code} status from rspamd, wanted 200"
          raise Error, "Error when scanning with rspamd (got #{response.code})"
        end

        response
      end

    end
  end
end

View on GitHub (pinned to d038eaa8c7)

Solutions

  1. Confirm rspamd is running and reachable from the Postal host: curl -v http://<host>:<port>/ping
  2. Correct host/port/ssl in the message_inspectors.rspamd section of postal.yml and restart Postal
  3. If timeouts are the cause (slow rspamd under load), give rspamd more resources or check its logs for stalls
  4. Confirm network paths (docker network, firewall) allow Postal to reach the rspamd port
  5. Watch the Postal log for the preceding 'Error talking to rspamd: <Class> (<message>)' line - it names the real network failure

Example fix

# before (postal.yml)
message_inspectors:
  rspamd:
    host: 127.0.0.1
    port: 11333
# ECONNREFUSED because rspamd runs in another container

# after
message_inspectors:
  rspamd:
    host: rspamd
    port: 11334
    ssl: true
# matches the rspamd container's service name and TLS controller port
Defensive patterns

Strategy: retry

Validate before calling

# pre-flight reachability check for the rspamd controller
require "socket"
require "openssl"
sock = TCPSocket.new(config.host, config.port)
begin
  sock = OpenSSL::SSL::SSLSocket.new(sock).connect if config.ssl
ensure
  sock.close
end

Type guard

def rspamd_reachable?(config)
  TCPSocket.new(config.host, config.port).close
  true
rescue StandardError
  false
end

Try / catch

# inside a custom inspector wrapper around Postal's Rspamd inspector
begin
  inspector.inspect_message(inspection)
rescue Postal::MessageInspectors::Rspamd::Error => e
  # transient transport failure: retry a bounded number of times with backoff,
  # then record the degraded result (Postal itself already adds an ERROR spam check)
  retry if (attempts += 1) < 3
end

Prevention

When it happens

Trigger: Delivering/scanning a message while rspamd is stopped or unreachable at the configured host/port; wrong host, port, or ssl setting in the message_inspectors.rspamd config; rspamd too slow so the 10 second read/open timeout trips; TLS handshake failure when ssl is enabled but the port is plain HTTP.

Common situations: rspamd container/service not started after deploy or host reboot; config pointing at 127.0.0.1 while rspamd runs in a different container/network; port mismatch (default controller port vs worker port); rspamd overloaded and slow; firewall between Postal and rspamd.

Related errors


AI-assisted analysis of postalserver/postal@d038eaa8c7 (2026-08-21). Data as JSON: /api/errors/3cd092e02a037e58. Report an issue: GitHub.