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

Error when scanning with rspamd (got #{response.code})

Error message

Error when scanning with rspamd (got #{response.code})

What it means

The rspamd inspector requires an HTTP 200 from /checkv2; any other status (401 invalid Password header, 403 forbidden, 413 oversized message, 500 rspamd internal error) is logged ('Got <code> status from rspamd, wanted 200') and raised as Rspamd::Error with the code interpolated. As with the transport error, inspect_message catches it and records a SpamCheck named ERROR, so mail proceeds without spam results.

Source

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

          # 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. Align the password: message_inspectors.rspamd.password in postal.yml must equal rspamd's controller password, then restart both
  2. Check rspamd's own logs at the timestamp to see why it returned the non-200 code
  3. If 413/size-related, raise rspamd max_size or inspect before attachment-heavy traffic
  4. After a rspamd upgrade, run rspamd configtest and fix broken symbols/maps that cause 500s
  5. Confirm the port really is the controller (/checkv2 endpoint), not another rspamd worker port that returns 405/404

Example fix

# before (postal.yml)
message_inspectors:
  rspamd:
    host: rspamd
    port: 11334
    ssl: true
    password: old-secret   # -> 'Got 401 status from rspamd'

# after
message_inspectors:
  rspamd:
    host: rspamd
    port: 11334
    ssl: true
    password: <%= ENV["RSPAMD_PASSWORD"] %>  # same value rspamd starts with
Defensive patterns

Strategy: validation

Validate before calling

# verify credentials/config against rspamd before relying on scanning
require "net/http"
http = Net::HTTP.new(config.host, config.port)
http.use_ssl = true if config.ssl
req = Net::HTTP::Get.new("/ping")
req["Password"] = config.password if config.password
response = http.request(req)
raise ArgumentError, "rspamd auth/config invalid: #{response.code}" unless response.code.to_i == 200

Type guard

def rspamd_config_valid?(config)
  # cheap authenticated probe: /ping must return 200 with the same headers /checkv2 uses
  response = rspamd_request(config, Net::HTTP::Get.new("/ping"))
  response.is_a?(Net::HTTPOK)
rescue StandardError
  false
end

Try / catch

begin
  inspector.inspect_message(inspection)
rescue Postal::MessageInspectors::Rspamd::Error => e
  if e.message.include?("got ")
    # HTTP-level rejection (auth/size/config): fix config; retrying the same message rarely helps
  end
end

Prevention

When it happens

Trigger: Scanning a message when the configured rspamd password does not match rspamd's own controller password (401); a message larger than rspamd's max-size (413/502 depending on version); rspamd returning 500 because of broken symbol/map configuration; requesting flags rspamd rejects.

Common situations: Password rotated on one side only (postal.yml vs rspamd's .env/controller config); large attachments tripping rspamd limits; rspamd upgraded with changed map/symbol syntax causing internal errors; a proxy in front of rspamd answering with its own error codes.

Related errors


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