spamc

package module
v0.0.0-...-a4e0c5c Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 9, 2020 License: MIT Imports: 15 Imported by: 2

README

GoDoc Build Status codecov

spamc is a Go client library for SpamAssassin's spamd daemon.

It started out as a fork of saintienn/go-spamc with some fixes, but has since been completely rewritten.

Basic example:

// Connect
c := New("127.0.0.1:783", &net.Dialer{
    Timeout: 20 * time.Second,
})
ctx := context.Background()

msg := strings.NewReader("Subject: Hello\r\n\r\nHey there!\r\n")

// Check if a message is spam.
check, err := c.Check(ctx, msg, nil)
if err != nil {
    log.Fatal(err)
}
fmt.Println(check.Score)

// Report ham for training.
tell, err := c.Tell(ctx, msg, Header{}.
    Set("Message-class", "ham").
    Set("Set", "local"))
if err != nil {
    log.Fatal(err)
}
fmt.Println(tell)

See godoc for the full documentation.

Runnings tests

Use ./bin/test to run all tests; use ./bin/test -b testsa to run tests that require a running SpamAssassin instance. This will automatically run SA in a Docker container. You can also use the SPAMC_SA_ADDRESS to set the SA address.

Documentation

Overview

Package spamc is a client library for SpamAssassin's spamd daemon. It provides functions for all the commands in the spamd protocol as specified here: http://svn.apache.org/repos/asf/spamassassin/trunk/spamd/PROTOCOL

All Client functions accept the message as an io.Reader and an optional map of Headers (which can be nil).

The Content-length header is mandatory. If the passed io.Reader is an strings.Reader, bytes.Reader, or os.File if will be added automatically. For other types you'll have to add it yourself:

conn.Check(ctx, msg, Header{}.Set("Content-length", size))

It is *strongly* recommended that the Header.Set function is used instead of directly setting the map. This ensures that the correct capitalisation is used; using the Content-Length header is a fatal error ("l" in length needs to be lower-case).

Example
// Connect
c := New("127.0.0.1:783", &net.Dialer{
	Timeout: 20 * time.Second,
})
ctx := context.Background()

msg := strings.NewReader("Subject: Hello\r\n\r\nHey there!\r\n")

// Check if a message is spam.
check, err := c.Check(ctx, msg, nil)
if err != nil {
	log.Fatal(err)
}
fmt.Println(check.Score)

// Report ham for training.
tell, err := c.Tell(ctx, msg, Header{}.
	Set("Message-class", "ham").
	Set("Set", "local"))
if err != nil {
	log.Fatal(err)
}
fmt.Println(tell)
Output:

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Client

type Client struct {
	// DefaultUser is the User to send if a command didn't specify one.
	DefaultUser string
	// contains filtered or unexported fields
}

Client is a connection to the spamd daemon.

func New

func New(addr string, d Dialer) *Client

New created a new Client instance.

The addr should be as "host:port"; as dialer most people will want to use net.Dialer:

New("127.0.0.1:783", &net.Dialer{Timeout: 20 * time.Second})

If the passed dialer is nil then this will be used as a default.

func (*Client) Check

func (c *Client) Check(
	ctx context.Context,
	msg io.Reader,
	hdr Header,
) (*ResponseCheck, error)

Check if the passed message is spam.

func (*Client) Headers

func (c *Client) Headers(
	ctx context.Context,
	msg io.Reader,
	hdr Header,
) (*ResponseProcess, error)

Headers is the same as Process() but returns only modified headers and not the body.

Do not forget to close the Message reader!

func (*Client) Ping

func (c *Client) Ping(ctx context.Context) error

Ping returns a confirmation that spamd is alive.

func (*Client) Process

func (c *Client) Process(
	ctx context.Context,
	msg io.Reader,
	hdr Header,
) (*ResponseProcess, error)

Process this message and return a modified message.

Do not forget to close the Message reader!

func (*Client) Report

func (c *Client) Report(
	ctx context.Context,
	msg io.Reader,
	hdr Header,
) (*ResponseReport, error)

Report gives a detailed textual report for the message.

func (*Client) ReportIfSpam

func (c *Client) ReportIfSpam(
	ctx context.Context,
	msg io.Reader,
	hdr Header,
) (*ResponseReport, error)

ReportIfSpam gives a detailed textual report for the message if it is considered spam. If it's not it will set just the spam score.

func (*Client) Symbols

func (c *Client) Symbols(
	ctx context.Context,
	msg io.Reader,
	hdr Header,
) (*ResponseSymbols, error)

Symbols checks if the message is spam and returns the score and a list of all symbols that were hit.

func (*Client) Tell

func (c *Client) Tell(
	ctx context.Context,
	msg io.Reader,
	hdr Header,
) (*ResponseTell, error)

Tell what type of we are to process and what should be done with that message.

This includes setting or removing a local or a remote database (learning, reporting, forgetting, revoking).

Message-class clasifies the message you're sending, and either the Set or Remove header specifies which action you want to take.

To learn a message as spam:

c.Tell(ctx, msg, Header{}.
    Set("Message-class", "spam").
    Set("Set", "local"))

Or to learn a message as ham:

c.Tell(ctx, msg, Header{}.
    Set("Message-class", "ham").
    Set("Set", "local"))

type Dialer

type Dialer interface {
	DialContext(ctx context.Context, network, address string) (net.Conn, error)
}

Dialer to connect to spamd; usually a net.Dialer instance.

type Error

type Error struct {
	Code int64  // Code from spamd
	Line string // Line of text from spamd, unaltered.
	// contains filtered or unexported fields
}

Error is used for spamd responses; it contains the spamd exit code.

func (Error) Error

func (e Error) Error() string
type Header map[string]string

Header for requests and responses.

func (Header) Get

func (h Header) Get(k string) (string, bool)

Get a header value; the second return value indicates if the map has this key.

func (Header) Iterate

func (h Header) Iterate() [][]string

Iterate over the map in alphabetical order.

func (Header) Set

func (h Header) Set(k, v string) Header

Set a header. This will normalize the key casing, which is important because SpamAssassin may ignore the header otherwise.

The map is modified in-place, but is also returned for easier use:

fun(Header{}.Set("key", "value").Set("foo", "bar"))

type Report

type Report struct {
	Intro string
	Table []struct {
		Points      float64
		Rule        string
		Description string
	}
}

Report contains the parsed results of the Report command.

func (Report) String

func (r Report) String() string

String formats the reports like SpamAssassin.

type ResponseCheck

type ResponseCheck struct {
	ResponseScore
}

ResponseCheck is the response from the Check command.

type ResponseProcess

type ResponseProcess struct {
	ResponseScore

	// Message headers and body.
	Message io.ReadCloser
}

ResponseProcess is the response from the Process and Headers commands.

type ResponseReport

type ResponseReport struct {
	ResponseScore

	// Report broken down in the found rules and their descriptions.
	Report Report
}

ResponseReport is the response from the Report and ReportIfSpam commands.

type ResponseScore

type ResponseScore struct {
	IsSpam    bool    // IsSpam reports if this message is considered spam.
	Score     float64 // Score is the spam score of this message.
	BaseScore float64 // BaseScore is the "minimum spam score" configured on the server.
}

ResponseScore contains the Spam score of this email; used in various different responses.

type ResponseSymbols

type ResponseSymbols struct {
	ResponseScore

	// Symbols that matched.
	Symbols []string
}

ResponseSymbols is the response from the Symbols command.

type ResponseTell

type ResponseTell struct {
	DidSet    []string
	DidRemove []string
}

ResponseTell is the response of a TELL command.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL