Help Needed for rspamd support

I’m trying to filter outbound email, only letting high-quality (non-spammy) messages go out based on Spamassassin score, is this possible in Kumomta somehow?

IIRC @fhf has done this, you call the API via Lua.

any example? using kumo.http ?

rspamd provides a rest API, you just post the full message data msg:get_data() to it and it returns the spam score, but it can be slow depending on the plugins and checks you’ve enabled in rspamd, which is why I don’t do it directly in kumo before sending. I do it after the email has been sent in my a separate service, and keep track of the spam score for the tenant and suspend the account if the spam score is high.

but it should be easy to do in kumo/lua as well. you can see the documentation for the rspamd API here Rspamd protocol | Rspamd Documentation

Something like this should work:

RSPAMD_URL = "http://localhost:11333/checkv2"


kumo.on('smtp_server_message_received', function(msg)
  local request = kumo.http.build_client({}):post(RSPAMD_URL)
  request:body(msg:get_data())
  local response = request:send()
  if response:status_code() == 200 then
    local data = kumo.serde.json_parse(response:text())
    if data['score'] >= 15 then -- rspamd recommends rejecting the message
      kumo.reject(550, 'We do not send spam')
    end
  end
  -- the rest of your handler 
end

You’ll also have to make some changes to rspamd config, by default it’s expecting inbound emails and does a lot of unnecessary checks that increase the score unnecessarily.

But as I mentioned earlier, I don’t recommend doing this in Lua because it will slow down your email processing. Instead, I’ve set up a separate system to handle spam checks.

  • Kumo sends message data (msg:get_data()) to the external system.
  • The external system launches a non-blocking check in a separate thread
  • It immediately responds with an HTTP 200 OK to Kumo, so Kumo can continue sending the email without waiting for the spam check to complete.

When the check finishes in the external system, the spam score and payload are saved to a database which is then used to calculate tenant-level spam scores and suspend tenants if their spam rate is too high (and I have the data to do manual verifications and checks later in case a tenant is suspended due to a false positive).

The external system also tracks tenant reputation based on factors like account age, sending volume, bounce rates, feedback loop (FBL) reports, average spam scores (from rspamd), and a few other things. Using this reputation data, it decides what percentage of messages to check for each tenant and can automatically suspend tenants if their bounce/FBL/spam rate is high.

You will end up sending out a few bad messages, but you can adjust the thresholds to have the offending tenants suspended pretty quickly. I also use an LLM to check for spam/phishing and ToS violations (again, by sampling messages based on reputation), and the combined systems has gotten very good at recognizing bad actors and they pretty much always get automatically suspended within the first 10 messages they send (often by the first 1-3 messages).

That would be pretty good than waiting every msg and it’s score. Thanks for sharing