Cloudron makes it easy to run web apps like WordPress, Nextcloud, GitLab on your server. Find out more or install now.


Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Bookmarks
  • Search
Skins
  • Light
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Brand Logo

Cloudron Forum

Apps - Status | Demo | Docs | Install
  1. Cloudron Forum
  2. Support
  3. Mail app: optional SpamAssassin plugins can't be enabled with their stock rules, and `sa-update` never runs

Mail app: optional SpamAssassin plugins can't be enabled with their stock rules, and `sa-update` never runs

Scheduled Pinned Locked Moved Unsolved Support
spamassassin
11 Posts 4 Posters 106 Views 4 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • imc67I Offline
    imc67I Offline
    imc67
    translator
    wrote last edited by
    #1

    Running three Cloudron servers (9.2.x, mail app 3.18.2, SpamAssassin 4.0.0) with
    about 35 mailboxes between them. While hardening against a run of phishing that
    was getting through, I went looking at how SpamAssassin is set up inside the mail
    container and found a few things that I think are worth sharing — plus some
    questions I couldn't answer from the docs.

    Everything below is reproducible with docker exec mail … on the host.

    1. The optional plugins are off — but that's upstream, not Cloudron

    My first assumption was that Cloudron had disabled them. It hasn't:

    docker exec mail dpkg -V spamassassin
    ??5??????  c /etc/spamassassin/local.cf
    ??5??????  c /etc/spamassassin/v310.pre
    

    Only local.cf and v310.pre differ from the Debian package. v342.pre is
    byte-identical
    , and that is the file holding Phishing, FromNameSpoof,
    DecodeShortURLs, URILocalBL and PhishTag — all commented out exactly as
    upstream ships them. So this is stock SpamAssassin behaviour, and I want to be
    clear I'm not reporting a Cloudron bug here. It only becomes a Cloudron question
    because of point 2.

    For completeness, Cloudron's entire spamd setup is this, from /app/code/start.sh:

    setup_spamd() {
        mkdir -p /run/spamd /app/data/spamd /run/spamd/tmp
        touch /app/data/spamd/custom.cf /app/data/spamd/acl.cf
        chown -R cloudron:cloudron /app/data/spamd /run/spamd
    }
    

    2. loadplugin works from custom.cf, but the stock rules don't come with it

    The only persistent config surface is the Custom SpamAssassin rules field in
    the Email view, which is /app/data/spamd/custom.cf, included at the end of
    local.cf. Anything in /etc/spamassassin/ is reset on app update.

    loadplugin is accepted there and lints clean:

    docker exec mail spamassassin --lint --cf="loadplugin Mail::SpamAssassin::Plugin::FromNameSpoof"
    # exit 0
    

    But it has no effect on the plugin's own rules. Those live in
    /usr/share/spamassassin/72_active.cf behind an ifplugin guard, and that file
    is parsed before local.cf pulls in custom.cf — so by the time the plugin
    loads, the guard has already been evaluated and the rules skipped for good.

    Verified with a message whose From: display name is the recipient's address
    (should trip T_FROMNAME_EQUALS_TO😞

    # without the plugin
    tests=FROM_2_EMAILS_SHORT,…            score=3.0
    
    # with --cf="loadplugin …FromNameSpoof"
    tests=FROM_2_EMAILS_SHORT,…            score=3.0     ← identical
    

    Workaround that does work: load the plugin and redefine the rules yourself
    in custom.cf under your own names. That gives 3.0 → 4.9 on the same message:

    loadplugin Mail::SpamAssassin::Plugin::FromNameSpoof
    
    header   __MY_FROMNAME_SPOOF       eval:check_fromname_spoof()
    header   __MY_FROMNAME_EQUALS_TO   eval:check_fromname_equals_to()
    meta     MY_FROMNAME_SPOOFED_EMAIL (__MY_FROMNAME_SPOOF && !__VIA_ML && !__VIA_RESIGNER && !__RP_MATCHES_RCVD)
    meta     MY_FROMNAME_EQUALS_TO     __MY_FROMNAME_EQUALS_TO
    score    MY_FROMNAME_SPOOFED_EMAIL 0.01
    score    MY_FROMNAME_EQUALS_TO     0.01
    

    It works, but you're maintaining a copy of upstream's rule definitions, which
    will silently drift when SpamAssassin changes them.

    3. sa-update never runs

    This one surprised me more than the plugins:

    docker exec mail ls /var/lib/spamassassin/
    sa-update-keys                                  ← only the keys, no rules dir
    
    docker exec mail ls /etc/cron.d/                ← e2scrub_all, php
    docker exec mail grep -rn sa-update /app/code/start.sh /etc/supervisor/   ← nothing
    

    No versioned rules directory means sa-update has never completed. The static
    rule set is therefore whatever the Debian package ships —
    /usr/share/spamassassin/50_scores.cf is dated 2022-07-01 on my servers.

    In practice this matters less than it sounds, because the adaptive parts are all
    still live: DNSBL/URIBL lookups are DNS queries and always current, Bayes trains
    itself, and custom.cf is mine. But rule updates also carry rescored weights
    from current corpora, and those never arrive.

    I can see why it isn't run: /var/lib/spamassassin isn't persistent, so any
    sa-update result is discarded on the next app update.

    4. Two smaller things

    • The Phishing plugin reads its feed file only in finish_parsing_end, i.e.
      once at spamd startup. Refreshing the feed on disk does nothing until
      supervisorctl restart spamd. I'm doing that from a host cron job; it works,
      but it feels like reaching around the platform.
    • Unrelated to Cloudron, but a time-saver for anyone else wiring up that plugin:
      https://openphish.com/feed.txt is now a 302 to a GitHub raw URL, so curl
      without -L silently writes an HTML error page over your feed. And the
      phishstats.info/phish_score.csv URL in the plugin's own documentation
      currently returns 404.

    Questions

    1. Is there a supported way to load a SpamAssassin plugin early enough that its
      stock ifplugin-guarded rules activate? A persistent .pre — or a second
      textarea next to the custom-rules field that gets written to a .pre — would
      solve it without anyone having to copy upstream rule definitions.
    2. Is not running sa-update a deliberate choice? If so, what's the reasoning,
      and is there a recommended way to keep the static rule set reasonably current
      given that /var/lib/spamassassin doesn't survive an app update?
    3. Would you consider enabling FromNameSpoof by default? It needs no external
      service, no feed, and no configuration, and display-name spoofing ("Rabobank"
      from a random domain) is one of the most common phishing shapes we see.
    4. For external data files that a plugin reads at startup (like the phishing
      feed): is a host cron doing docker exec mail supervisorctl restart spamd the
      intended approach, or is there a cleaner hook?

    Happy to test anything on my side — I have three servers and a corpus of real
    phishing that got through, so I can measure rather than guess.

    1 Reply Last reply
    0
    • girishG Offline
      girishG Offline
      girish
      Staff
      wrote last edited by
      #2

      There's too much AI text here to investigate but sa-update is now run periodically. I fixed this recently.

      Also, the plan is not to expose spamassassin and it's features/plugins. We will simply integrate the use cases and never implementation details. Currently, the custom SA config is allowed in the UI but this was a mistake on our side.

      d19dotcaD 1 Reply Last reply
      0
      • imc67I Offline
        imc67I Offline
        imc67
        translator
        wrote last edited by imc67
        #3

        sorry @girish it was indeed written by Claude Code Opus 5. But realise that in this AI world I noticed on my 3 Cloudron-servers a huge increase of attacks, spam and phishing (and the last one was once "successful" for one user with nasty results).

        As far as I can see the default "anti-spam / anti-phishing" in Cloudron is absolutely not sufficient, @d19dotca was "the pioneer" here on the forum with custom SA rules and I fight "attackers with AI" with my own "AI" 😃.

        The only thing I ask you devs is to increase attention for "attacks, spam and phishing" and tell me what I can do if you don't/can't.

        1 Reply Last reply
        2
        • girishG Offline
          girishG Offline
          girish
          Staff
          wrote last edited by
          #4

          @imc67 no worries. But yeah fighting spam has become overly complicated and products don't exist yet to tackle this kind of scale.

          Currently, our gitlab is under attack. Almost 40k unique IPs. I took the IPs from our access.log and not some random blocklist. In fact, I blocked gitlab for everyone now and just put the company in a whitelist for the moment. I understand this is impractical for Email (our email too is under constant attack).

          353748d1-e075-4049-9c62-0e103c1efc90-image.jpeg

          imc67I andreasduerenA 2 Replies Last reply
          1
          • girishG girish

            @imc67 no worries. But yeah fighting spam has become overly complicated and products don't exist yet to tackle this kind of scale.

            Currently, our gitlab is under attack. Almost 40k unique IPs. I took the IPs from our access.log and not some random blocklist. In fact, I blocked gitlab for everyone now and just put the company in a whitelist for the moment. I understand this is impractical for Email (our email too is under constant attack).

            353748d1-e075-4049-9c62-0e103c1efc90-image.jpeg

            imc67I Offline
            imc67I Offline
            imc67
            translator
            wrote last edited by
            #5

            @girish indeed I noticed git.cloudron.io gave a 403.

            As you might remember I created my own "security monitor" for centrally monitoring and managing 3 Cloudron servers, it's growing with hundreds a day, the list below are lines, the unique IP's are 641.451.742 separate IPv4-adressess:
            Scherm­afbeelding 2026-07-29 om 10.02.05.png

            girishG 1 Reply Last reply
            1
            • imc67I imc67

              @girish indeed I noticed git.cloudron.io gave a 403.

              As you might remember I created my own "security monitor" for centrally monitoring and managing 3 Cloudron servers, it's growing with hundreds a day, the list below are lines, the unique IP's are 641.451.742 separate IPv4-adressess:
              Scherm­afbeelding 2026-07-29 om 10.02.05.png

              girishG Offline
              girishG Offline
              girish
              Staff
              wrote last edited by
              #6

              @imc67 wow 🙂 thing is in some of our servers even the hash list of the kernel is slow when adding so many IPs !

              (Sorry, for pulling down git.cloudron.io, I hope to unblock everything later in the day but package updates requires gitlab to be stable)

              1 Reply Last reply
              1
              • imc67I Offline
                imc67I Offline
                imc67
                translator
                wrote last edited by
                #7

                haha (sorry) now you experience the same as I do, every hour the newly to be blocked IP's are pushed via API and it takes 4-6 minutes to be processed. That's why I suggested previously in a post to maken it "insert/update/delete" per IP or CIDR.

                Good luck!

                1 Reply Last reply
                0
                • girishG girish

                  @imc67 no worries. But yeah fighting spam has become overly complicated and products don't exist yet to tackle this kind of scale.

                  Currently, our gitlab is under attack. Almost 40k unique IPs. I took the IPs from our access.log and not some random blocklist. In fact, I blocked gitlab for everyone now and just put the company in a whitelist for the moment. I understand this is impractical for Email (our email too is under constant attack).

                  353748d1-e075-4049-9c62-0e103c1efc90-image.jpeg

                  andreasduerenA Offline
                  andreasduerenA Offline
                  andreasdueren
                  App Dev
                  wrote last edited by
                  #8

                  @girish said:
                  Currently, our gitlab is under attack. Almost 40k unique IPs. I took the IPs from our access.log and not some random blocklist.

                  oh that explains the downtime it had these days lol

                  1 Reply Last reply
                  0
                  • girishG Offline
                    girishG Offline
                    girish
                    Staff
                    wrote last edited by
                    #9

                    It's back now

                    1 Reply Last reply
                    1
                    • girishG girish

                      There's too much AI text here to investigate but sa-update is now run periodically. I fixed this recently.

                      Also, the plan is not to expose spamassassin and it's features/plugins. We will simply integrate the use cases and never implementation details. Currently, the custom SA config is allowed in the UI but this was a mistake on our side.

                      d19dotcaD Offline
                      d19dotcaD Offline
                      d19dotca
                      wrote last edited by d19dotca
                      #10

                      @girish said:

                      Also, the plan is not to expose spamassassin and it's features/plugins. We will simply integrate the use cases and never implementation details. Currently, the custom SA config is allowed in the UI but this was a mistake on our side.

                      Hmm, I am not sure if I agree with that view. Why do you think that was a mistake? If it wasn't customizable, many of us would be getting many more times the spam we already do because the default SpamAssassin rules are pretty awful these days with the aggressive spam nature as a result of so many more bots and more sophisticated spam attacks.

                      Please don't remove that. If anything, I am in agreement with @imc67 that we need more controls. Cloudron is maturing, and with the help of AI many people are getting more advanced in their skillsets, and hiding things away from technical admins only increase friction with using Cloudron. I do hope that this will be reconsidered, and that more controls can be exposed for us.


                      On a separate note about the SpamAssassin sa-update and sa-learn stuff that Cloudron has a script for, I was recently looking into that myself and comparing it with a script I wrote myself for running some SpamAssassin scans for learning ham and spam (BAYES training). Here is an AI summary of this for reference:

                      The bundled /app/code/spamassassin-config/learn-from-user-mail.sh, scheduled daily at 22:00 UTC by /app/code/service.js, only identifies paths under .Spam as spam.
                      
                      Its ham search excludes exact .Drafts, .Spam, and .Trash paths, but it does not correctly handle:
                      
                      - .Junk or nested Junk folders, which are learned as ham
                      - .Deleted Messages, which is learned as ham
                      - nested Trash folders such as .Trash.CANCELLATIONS
                      - Sent/Sent Messages, with no option for administrators to exclude them
                      - folder and message paths containing spaces, because results from find are processed through whitespace-splitting shell variables
                      - messages above the default spamc 512 KB limit
                      
                      The script also applies head -n 200 to unsorted find output, so the selected messages are not necessarily the newest 200.
                      
                      Could the learner use Dovecot special-use metadata (\Junk, \Trash, \Sent, and \Drafts) or, at minimum, robust Maildir folder-name matching with NUL-delimited paths?
                      
                      It would also be helpful to make Sent-folder learning configurable and provide an administrator option to disable or customize the bundled automatic learner.
                      

                      --
                      Dustin Dauncey
                      www.d19.ca

                      girishG 1 Reply Last reply
                      3
                      • d19dotcaD d19dotca

                        @girish said:

                        Also, the plan is not to expose spamassassin and it's features/plugins. We will simply integrate the use cases and never implementation details. Currently, the custom SA config is allowed in the UI but this was a mistake on our side.

                        Hmm, I am not sure if I agree with that view. Why do you think that was a mistake? If it wasn't customizable, many of us would be getting many more times the spam we already do because the default SpamAssassin rules are pretty awful these days with the aggressive spam nature as a result of so many more bots and more sophisticated spam attacks.

                        Please don't remove that. If anything, I am in agreement with @imc67 that we need more controls. Cloudron is maturing, and with the help of AI many people are getting more advanced in their skillsets, and hiding things away from technical admins only increase friction with using Cloudron. I do hope that this will be reconsidered, and that more controls can be exposed for us.


                        On a separate note about the SpamAssassin sa-update and sa-learn stuff that Cloudron has a script for, I was recently looking into that myself and comparing it with a script I wrote myself for running some SpamAssassin scans for learning ham and spam (BAYES training). Here is an AI summary of this for reference:

                        The bundled /app/code/spamassassin-config/learn-from-user-mail.sh, scheduled daily at 22:00 UTC by /app/code/service.js, only identifies paths under .Spam as spam.
                        
                        Its ham search excludes exact .Drafts, .Spam, and .Trash paths, but it does not correctly handle:
                        
                        - .Junk or nested Junk folders, which are learned as ham
                        - .Deleted Messages, which is learned as ham
                        - nested Trash folders such as .Trash.CANCELLATIONS
                        - Sent/Sent Messages, with no option for administrators to exclude them
                        - folder and message paths containing spaces, because results from find are processed through whitespace-splitting shell variables
                        - messages above the default spamc 512 KB limit
                        
                        The script also applies head -n 200 to unsorted find output, so the selected messages are not necessarily the newest 200.
                        
                        Could the learner use Dovecot special-use metadata (\Junk, \Trash, \Sent, and \Drafts) or, at minimum, robust Maildir folder-name matching with NUL-delimited paths?
                        
                        It would also be helpful to make Sent-folder learning configurable and provide an administrator option to disable or customize the bundled automatic learner.
                        
                        girishG Offline
                        girishG Offline
                        girish
                        Staff
                        wrote last edited by girish
                        #11

                        @d19dotca both the statements are orthogonal. Cloudron can provide feature to tackle spam and make it more accessible for all users. At the same time, Cloudron can also not expose implementation details like SpamAssassin configs. In fact, there are newer solutions out there like say rspamd which even help with integrating email with LLM. But because Cloudron exposed SA we are now "stuck" and possibly have to break support at some point.

                        We have always taken this approach to our product, so it's not anything new. We don't expose docker configs, haraka configs, dovecot configs, nginx configs etc. It's not how we do things. The SpamAssasin config was done only because an immediate problem had to be fixed and was done in haste.

                        1 Reply Last reply
                        1

                        Hello! It looks like you're interested in this conversation, but you don't have an account yet.

                        Getting fed up of having to scroll through the same posts each visit? When you register for an account, you'll always come back to exactly where you were before, and choose to be notified of new replies (either via email, or push notification). You'll also be able to save bookmarks and upvote posts to show your appreciation to other community members.

                        With your input, this post could be even better 💗

                        Register Login
                        Reply
                        • Reply as topic
                        Log in to reply
                        • Oldest to Newest
                        • Newest to Oldest
                        • Most Votes


                        • Login

                        • Don't have an account? Register

                        • Login or register to search.
                        • First post
                          Last post
                        0
                        • Categories
                        • Recent
                        • Tags
                        • Popular
                        • Bookmarks
                        • Search