A Go library to write mail filters.
- With this library you can write both the client (MTA/SMTP-Server) and server (milter filter) in pure Go without sendmail's libmilter.
- Easy wrapper of the milter protocol that abstracts away many milter protocol quirks and lets you write mail filters with little effort.
- UTF-8 support
- IDNA support
- Client & Server support milter protocol version 6 with all features. E.g.:
- all milter events including DATA, UNKNOWN, ABORT and QUIT NEW CONNECTION
- milter can skip e.g. body chunks when it does not need all chunks
- milter can send progress notifications when response can take some time
- milter can automatically instruct the MTA which macros it needs.
- Automatic integration tests that test the compatibility with Postfix and Sendmail.
go get -u github.com/d--j/go-milter
The following example is a milter filter that adds [⚠️EXTERNAL]
to the subject of all messages of unauthenticated users.
See GoDoc for more documentation and an example for a milter client or a raw milter server.
package main
import (
"context"
"flag"
"log"
"strings"
"github.com/d--j/go-milter/mailfilter"
)
func main() {
// parse commandline arguments
var protocol, address string
flag.StringVar(&protocol, "proto", "tcp", "Protocol family (unix or tcp)")
flag.StringVar(&address, "addr", "127.0.0.1:10003", "Bind to address or unix domain socket")
flag.Parse()
// create and start the mail filter
mailFilter, err := mailfilter.New(protocol, address,
func(_ context.Context, trx mailfilter.Trx) (mailfilter.Decision, error) {
// Quarantine mail when it is addressed to our SPAM trap
if trx.HasRcptTo("spam-trap@スパム.example.com") {
return mailfilter.QuarantineResponse("train as spam"), nil
}
// Prefix subject with [⚠️EXTERNAL] when user is not logged in
if trx.MailFrom().AuthenticatedUser() == "" {
subject, _ := trx.Headers().Subject()
if !strings.HasPrefix(subject, "[⚠️EXTERNAL] ") {
subject = "[⚠️EXTERNAL] " + subject
trx.Headers().SetSubject(subject)
}
}
return mailfilter.Accept, nil
},
// optimization: call the decision function when all headers were sent to us
mailfilter.WithDecisionAt(mailfilter.DecisionAtEndOfHeaders),
)
if err != nil {
log.Fatal(err)
}
log.Printf("Started milter on %s:%s", mailFilter.Addr().Network(), mailFilter.Addr().String())
// wait for the mail filter to end
mailFilter.Wait()
}
BSD 2-Clause
Based on https://github.com/emersion/go-milter by Simon Ser which is based on https://github.com/phalaaxx/milter by Bozhin Zafirov. Max Mazurov made major contributions to this code as well.