Integrating Roundcube "Mark as Junk" Plugin with SpamAssassin (Bayes) Train on DirectAdmin

This tutorial provides a complete, production-ready guide to integrating the Mark as Junk plugin in Roundcube Webmail with SpamAssassin (sa-learn) on a DirectAdmin server. Using sudoers permissions for the webapps user ensures that Bayes training updates the correct per-user SpamAssassin database securely and without permission errors.

Prerequisites: Root SSH access to your DirectAdmin server running CustomBuild and SpamAssassin.

Step 1: Create the Main Learning Script

Create the master script that receives the email payload from Roundcube and passes it to sa-learn under the specific DirectAdmin user context:

cat > /usr/local/bin/rc-sa-learn.sh << 'SCRIPT'
#!/bin/bash
TYPE="$1"
DOMAIN="$2"
MSGFILE="$3"

DAUSER=$(grep -i "^${DOMAIN}:" /etc/virtual/domainowners 2>/dev/null | awk -F': ' '{print $2}' | tr -d '[:space:]')

if [ -z "$DAUSER" ]; then
    echo "$(date): ERROR - could not resolve DA user for domain $DOMAIN" >> /var/log/rc-sa-learn.log
    exit 1
fi

BAYESPATH="/home/${DAUSER}/.spamassassin/bayes"

if [ "$TYPE" = "spam" ]; then
    sudo -u "$DAUSER" /usr/bin/sa-learn --spam --dbpath="$BAYESPATH" "$MSGFILE" >> /var/log/rc-sa-learn.log 2>&1
elif [ "$TYPE" = "ham" ]; then
    sudo -u "$DAUSER" /usr/bin/sa-learn --ham --dbpath="$BAYESPATH" "$MSGFILE" >> /var/log/rc-sa-learn.log 2>&1
fi

if [ $? -ne 0 ]; then
    echo "$(date): WARNING - sa-learn failed for user $DAUSER (missing sudoers entry? run /root/bootstrap-sa-learn-sudoers.sh)" >> /var/log/rc-sa-learn.log
fi
SCRIPT

chmod +x /usr/local/bin/rc-sa-learn.sh
touch /var/log/rc-sa-learn.log
chmod 666 /var/log/rc-sa-learn.log

Step 2: Automate Sudoers Rules for New Users (DirectAdmin Hook)

Set up a DirectAdmin post-user-creation script to automatically grant the webapps user passwordless sudo permissions for running sa-learn under newly created accounts:

mkdir -p /usr/local/directadmin/scripts/custom

cat > /usr/local/directadmin/scripts/custom/user_create_post.sh << 'SCRIPT'
#!/bin/sh
DAUSER="${username}"

if [ -z "$DAUSER" ]; then
    exit 0
fi

SUDOFILE="/etc/sudoers.d/sa-learn-${DAUSER}"

if [ ! -f "$SUDOFILE" ]; then
    cat > "$SUDOFILE" << EOF
webapps ALL=(${DAUSER}) NOPASSWD: /usr/bin/sa-learn --spam --dbpath=/home/${DAUSER}/.spamassassin/bayes *
webapps ALL=(${DAUSER}) NOPASSWD: /usr/bin/sa-learn --ham --dbpath=/home/${DAUSER}/.spamassassin/bayes *
EOF
    chmod 440 "$SUDOFILE"
    visudo -cf "$SUDOFILE" >/dev/null 2>&1 || rm -f "$SUDOFILE"
fi

exit 0;
SCRIPT

chmod 700 /usr/local/directadmin/scripts/custom/user_create_post.sh
chown diradmin:diradmin /usr/local/directadmin/scripts/custom/user_create_post.sh

Step 3: Provision Sudoers Rules for Existing Users

Create and execute a bootstrap script to generate the appropriate sudoers entries for all existing DirectAdmin users:

cat > /root/bootstrap-sa-learn-sudoers.sh << 'SCRIPT'
#!/bin/bash
while IFS=': ' read -r DOMAIN DAUSER; do
    DAUSER=$(echo "$DAUSER" | tr -d '[:space:]')
    [ -z "$DAUSER" ] && continue
    SUDOFILE="/etc/sudoers.d/sa-learn-${DAUSER}"
    if [ ! -f "$SUDOFILE" ]; then
        cat > "$SUDOFILE" << EOF
webapps ALL=(${DAUSER}) NOPASSWD: /usr/bin/sa-learn --spam --dbpath=/home/${DAUSER}/.spamassassin/bayes *
webapps ALL=(${DAUSER}) NOPASSWD: /usr/bin/sa-learn --ham --dbpath=/home/${DAUSER}/.spamassassin/bayes *
EOF
        chmod 440 "$SUDOFILE"
        visudo -cf "$SUDOFILE" >/dev/null 2>&1 && echo "Provisioned: $DAUSER" || { rm -f "$SUDOFILE"; echo "FAILED (invalid): $DAUSER"; }
    fi
done < /etc/virtual/domainowners
SCRIPT

chmod +x /root/bootstrap-sa-learn-sudoers.sh
/root/bootstrap-sa-learn-sudoers.sh

Verify that the rules were created successfully:

ls /etc/sudoers.d/ | grep sa-learn

Step 4: Configure the Mark as Junk Plugin

Locate the active Roundcube webmail path and edit the plugin configuration:

RCPATH=$(find /var/www/webapps -maxdepth 1 -type d -iname "roundcubemail-*" | head -1)
echo "Live path: $RCPATH"

cp "$RCPATH/plugins/markasjunk/config.inc.php.dist" "$RCPATH/plugins/markasjunk/config.inc.php"

sed -i \
  -e "s|\$config\['markasjunk_learning_driver'\] = null;|\$config['markasjunk_learning_driver'] = 'cmd_learn';|" \
  -e "s|\$config\['markasjunk_spam_cmd'\] = null;|\$config['markasjunk_spam_cmd'] = '/usr/local/bin/rc-sa-learn.sh spam %d %f';|" \
  -e "s|\$config\['markasjunk_ham_cmd'\] = null;|\$config['markasjunk_ham_cmd'] = '/usr/local/bin/rc-sa-learn.sh ham %d %f';|" \
  -e "s|\$config\['markasjunk_debug'\] = false;|\$config['markasjunk_debug'] = true;|" \
  "$RCPATH/plugins/markasjunk/config.inc.php"

Confirm the plugin configuration parameters:

grep -E "learning_driver|spam_cmd|ham_cmd|debug" "$RCPATH/plugins/markasjunk/config.inc.php"

Step 5: DirectAdmin CustomBuild Persistent Setup

Copy configuration and plugin files into the CustomBuild directory structure to ensure changes are retained across updates:

mkdir -p /usr/local/directadmin/custombuild/custom/roundcube

cp "$RCPATH/config/config.inc.php" /usr/local/directadmin/custombuild/custom/roundcube/config.inc.php

chmod 640 /usr/local/directadmin/custombuild/custom/roundcube/config.inc.php

RCPLUGINCONFIG="/usr/local/directadmin/custombuild/custom/roundcube/config.inc.php"


if ! grep -qE "['\"]markasjunk['\"]" "$RCPLUGINCONFIG"; then
  sed -i -E "s|(\\\$config\['plugins'\]\s*=\s*\[[^]]*)\]|\1, 'markasjunk']|" "$RCPLUGINCONFIG"
fi


grep -E "plugins" "$RCPLUGINCONFIG"

mkdir -p /usr/local/directadmin/custombuild/custom/roundcube/plugins

cp -r "$RCPATH/plugins/markasjunk" /usr/local/directadmin/custombuild/custom/roundcube/plugins/

Step 6: Rebuild Roundcube and Restart Services

Recompile Roundcube via CustomBuild and restart Exim and SpamAssassin:

cd /usr/local/directadmin/custombuild
./build roundcube

systemctl restart spamd
da build exim_conf

Step 7: Verification and Logs

  1. Log into Roundcube Webmail interface.
  2. Select an email and click Mark as Junk (or As Not Junk).
  3. Check the log output to confirm successful processing:
    tail -20 /var/log/rc-sa-learn.log

Maintenance: Future Upgrade Workflow

When upgrading Roundcube via CustomBuild in the future, automatically resolve the active installation directory and compare your custom configuration files against the newly installed distribution files to detect any new configuration flags:

RCPATH=$(find /var/www/webapps -maxdepth 1 -type d -iname "roundcubemail-*" | head -1)

# Check main configuration differences
diff /usr/local/directadmin/custombuild/custom/roundcube/config.inc.php "$RCPATH/config/config.inc.php"

# Check plugin configuration differences
diff /usr/local/directadmin/custombuild/custom/roundcube/plugins/markasjunk/config.inc.php "$RCPATH/plugins/markasjunk/config.inc.php.dist"

If any new $config[...] entries appear in the output, append or adapt them inside your custom configuration files under /usr/local/directadmin/custombuild/custom/roundcube/.

  • 1 Users Found This Useful
Was this answer helpful?

Related Articles

How to Configure DirectAdmin Spam Protection

Configuring proper server-wide spam protection is essential for maintaining server reputation,...