← Back to docs

SpamAssassin content scan API

SpamAssassin content scan API

Tools can submit WordPress comments, guestbook entries and other text content to one or more remote spamd servers over TCP.

Environment

Recommended production configuration:

SPAMASSASSIN_ENABLED=true
SPAMASSASSIN_SERVERS=62.171.175.28:783
SPAMASSASSIN_USER=debian-spamd
SPAMASSASSIN_CONNECT_TIMEOUT=2
SPAMASSASSIN_TIMEOUT=10
SPAMASSASSIN_CONNECT_RETRIES=1
SPAMASSASSIN_FILTER_RETRIES=1
SPAMASSASSIN_RETRY_SLEEP=1
SPAMASSASSIN_RANDOMIZE=false
SPAMASSASSIN_SSL=false
SPAMASSASSIN_SSL_CA_FILE=
SPAMASSASSIN_SSL_CERT_FILE=
SPAMASSASSIN_SSL_KEY_FILE=
SPAMASSASSIN_FAIL_OPEN=true
SPAMASSASSIN_MAX_CONTENT_BYTES=262144
SPAMASSASSIN_API_THROTTLE_PER_MINUTE=60

SPAMASSASSIN_USER is sent as the spamd User: header. The default mirrors the existing Postfix integration where spamc runs as debian-spamd; spamc normally sends its effective user identity to spamd for user/SQL preference selection.

Multiple backends are comma-separated and are tried in order by default:

SPAMASSASSIN_SERVERS=62.171.175.28:783,spamassassin-2.internal:783,spamassassin-3.internal:783

Set SPAMASSASSIN_RANDOMIZE=true only when randomized backend selection is desired instead of deterministic primary/failover behavior.

Remote spamd instances must allow TCP traffic from the Tools servers. Do not expose an unauthenticated spamd service to the public internet. Prefer firewall source allowlists/private networking. Enable TLS when the backend setup supports it.

Token permission

Content scanning uses the existing Tools token record with a separate spam_check permission. A token can therefore be dedicated to scanning without receiving DNSBL mutation permissions.

Admin management:

/admin/spamassassin/tokens

A dedicated scan token is created with:

  • allow_add=false
  • allow_delete=false
  • allow_custom_txt=false
  • allow_spam_check=true
  • is_admin_token=false

Admin tokens have effective scan permission automatically. Non-admin tokens are rate-limited independently by token, using SPAMASSASSIN_API_THROTTLE_PER_MINUTE; callers without a usable token fall back to an IP-based bucket.

API

Token information

GET /api/spamassassin/token/info
X-SpamAssassin-Token: <token>

The legacy/shared X-Dnsbl-Token header is also accepted so one token can carry multiple explicitly granted scopes.

Scan content

POST /api/spamassassin/scan
Content-Type: application/json
X-SpamAssassin-Token: <token>

{
  "content": "Example message with https://example.test/",
  "subject": "Optional title",
  "source_ip": "203.0.113.10",
  "source": "wordpress",
  "consumer": "tornevall-wp-dnsbl"
}

Successful response:

{
  "ok": true,
  "scan": {
    "is_spam": false,
    "score": 1.2,
    "required_score": 5,
    "rules": ["HTML_MESSAGE"]
  },
  "backend": {
    "status": "healthy",
    "index": 0,
    "attempts": 1
  }
}

Backend addresses are intentionally not exposed to API consumers. When the primary backend fails and a secondary succeeds, backend.status is degraded. When all backends fail, the endpoint returns HTTP 503 and includes the configured fail_open policy so callers can make an explicit moderation decision.

Privacy

The scan endpoint does not persist submitted raw content. Consumers should send only content required for spam classification and must never include passwords or unrelated profile data.