milter

package module
v0.0.0-...-659e4da Latest Latest
Warning

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

Go to latest
Published: Sep 10, 2019 License: BSD-2-Clause Imports: 10 Imported by: 0

README

GoDoc

This is an incompatible fork of https://github.com/mschneider82/milter, which is an excellent update to github.com/phalaaxx/milter.

API / Interface

The present API is not guaranteed to be stable though any changes will be minimized.

There were quite a few iterations as code using this evolved to get it to it's present state and now various projects depend on the interface not breaking.

Fork-Specific Changes

  • The interface has been altered from mschneider82's code such that it's now easier to determine the boundaries between messages.

  • The session and message IDs have been removed, they can be implemented in the specific Milter code if needed.

  • A small race in .Close() has been fixed.

  • Macros accumulate/mutate throughout the session and are now usable.

  • Testing; updated for new API. Milter is no longer embedded in the TestMilter as it's not necessary or desirable.

  • At least one chance after this was forked has been ignored so far (IPv6 addresses are working as expected for me, if a change is made to trim the IPv6 prefix is should probably only be done after checking it exists).

Rough Guide to the Lifecycle of Calls

NewSession is called at the start of milter session. EndSession is called when it's closed.

Connect is called once per session, it contains the string (name) of the remote host and it's address information.

Helo is called one (or more) times per session in response to HELO or EHLO.

Reset can be called at almost anytime to reset message-specific state, this corresponds to SMTPs RSET verb.

NewMessage is called before an email message is to be delivered. Usually you will see one message per session, but it's possible for there to be zero or two or more. Some high-performance MTAs will reuse SMTP connections so that you will see multiple messages from difference sources to different addresses in a given session.

MailFrom is called for MAIL FROM, one of which per message.

RcptTo is called for RCPT TO, one or more of which per message.

Header is called for head header passed in to the BODY stage of SMTP transaction.

Headers is called upon completion of all headers.

BodyChunk is called (possibly many times) with parts (chunks) of the message BODY.

Body is called upon completion of the entire BODY.

Example Sessions

Macros

Macros are available from some function at milter.Modifiers.Macros, these accumulate and mutate throughout the session. Some macro values are valid for the duration of the session, some are only valid for the current or previous message. The lifecycle of macros is not well defined, this usually isn't a problem for session level state but for things that change per-message use with care.

Documentation

Overview

A Go library for milter support

Index

Constants

View Source
const (
	RespAccept   = SimpleResponse(accept)
	RespContinue = SimpleResponse(continue_)
	RespDiscard  = SimpleResponse(discard)
	RespReject   = SimpleResponse(reject)
	RespTempFail = SimpleResponse(tempFail)
)

Define standard responses with no data

View Source
const (
	// set which actions the milter wants to perform
	OptNone           OptAction = 0x00  /* SMFIF_NONE no flags */
	OptAddHeader      OptAction = 0x01  /* SMFIF_ADDHDRS filter may add headers */
	OptChangeBody     OptAction = 0x02  /* SMFIF_CHGBODY filter may replace body */
	OptAddRcpt        OptAction = 0x04  /* SMFIF_ADDRCPT filter may add recipients */
	OptRemoveRcpt     OptAction = 0x08  /* SMFIF_DELRCPT filter may delete recipients */
	OptChangeHeader   OptAction = 0x10  /* SMFIF_CHGHDRS filter may change/delete headers */
	OptQuarantine     OptAction = 0x20  /* SMFIF_QUARANTINE filter may quarantine envelope */
	OptChangeFrom     OptAction = 0x40  /* SMFIF_CHGFROM filter may change "from" (envelope sender) */
	OptAddRcptPartial OptAction = 0x80  /* SMFIF_ADDRCPT_PAR filter may add recipients, including ESMTP parameter to the envelope.*/
	OptSetSymList     OptAction = 0x100 /* SMFIF_SETSYMLIST filter can send set of symbols (macros) that it wants */
	OptAllActions     OptAction = OptAddHeader | OptChangeBody | OptAddRcpt | OptRemoveRcpt | OptChangeHeader | OptQuarantine | OptChangeFrom | OptAddRcptPartial | OptSetSymList

	// mask out unwanted parts of the SMTP transaction
	OptNoConnect    OptProtocol = 0x01       /* SMFIP_NOCONNECT MTA should not send connect info */
	OptNoHelo       OptProtocol = 0x02       /* SMFIP_NOHELO MTA should not send HELO info */
	OptNoMailFrom   OptProtocol = 0x04       /* SMFIP_NOMAIL MTA should not send MAIL info */
	OptNoRcptTo     OptProtocol = 0x08       /* SMFIP_NORCPT MTA should not send RCPT info */
	OptNoBody       OptProtocol = 0x10       /* SMFIP_NOBODY MTA should not send body (chunk) */
	OptNoHeaders    OptProtocol = 0x20       /* SMFIP_NOHDRS MTA should not send headers */
	OptNoEOH        OptProtocol = 0x40       /* SMFIP_NOEOH MTA should not send EOH */
	OptNrHdr        OptProtocol = 0x80       /* SMFIP_NR_HDR SMFIP_NOHREPL No reply for headers */
	OptNoUnknown    OptProtocol = 0x100      /* SMFIP_NOUNKNOWN MTA should not send unknown commands */
	OptNoData       OptProtocol = 0x200      /* SMFIP_NODATA MTA should not send DATA */
	OptSkip         OptProtocol = 0x400      /* SMFIP_SKIP MTA understands SMFIS_SKIP */
	OptRcptRej      OptProtocol = 0x800      /* SMFIP_RCPT_REJ MTA should also send rejected RCPTs */
	OptNrConn       OptProtocol = 0x1000     /* SMFIP_NR_CONN No reply for connect */
	OptNrHelo       OptProtocol = 0x2000     /* SMFIP_NR_HELO No reply for HELO */
	OptNrMailFrom   OptProtocol = 0x4000     /* SMFIP_NR_MAIL No reply for MAIL */
	OptNrRcptTo     OptProtocol = 0x8000     /* SMFIP_NR_RCPT No reply for RCPT */
	OptNrData       OptProtocol = 0x10000    /* SMFIP_NR_DATA No reply for DATA */
	OptNrUnknown    OptProtocol = 0x20000    /* SMFIP_NR_UNKN No reply for UNKNOWN */
	OptNrEOH        OptProtocol = 0x40000    /* SMFIP_NR_EOH No reply for eoh */
	OptNrBody       OptProtocol = 0x80000    /* SMFIP_NR_BODY No reply for body chunk */
	OptHdrLeadSpace OptProtocol = 0x100000   /* SMFIP_HDR_LEADSPC header value leading space */
	OptMDS256K      OptProtocol = 0x10000000 /* SMFIP_MDS_256K MILTER_MAX_DATA_SIZE=256K */
	OptMDS1M        OptProtocol = 0x20000000 /* SMFIP_MDS_1M MILTER_MAX_DATA_SIZE=1M */
)
View Source
const (
	SMFIR_REPLYCODE = 'y' // SMFIR_REPLYCODE
)

Define milter response codes

Variables

View Source
var (
	ErrCloseSession = errors.New("Stop current milter processing")
	ErrMacroNoData  = errors.New("Macro definition with no data")
)

pre-defined errors

Functions

func Close

func Close() (err error)

Close server listener and wait worked process

func RunServer

func RunServer(server net.Listener, logger Logger, init MilterInit, handlers ...func(error)) error

RunServer provides a convenient way to start a milter server Handlers provide way to handle errors from panics With nil handlers panics not recovered

Types

type CustomResponse

type CustomResponse struct {
	// contains filtered or unexported fields
}

CustomResponse is a response instance used by callback handlers to indicate how the milter should continue processing of current message

func NewResponse

func NewResponse(code byte, data []byte) *CustomResponse

NewResponse generates a new CustomResponse suitable for WritePacket

func NewResponseStr

func NewResponseStr(code byte, data string) *CustomResponse

NewResponseStr generates a new CustomResponse with string payload code should be SMFIR_REPLYCODE == 'y' data can be "550 5.2.0 mailbox unavailable."

func (*CustomResponse) Continue

func (c *CustomResponse) Continue() bool

Continue returns false if milter chain should be stopped, true otherwise

func (*CustomResponse) Response

func (c *CustomResponse) Response() *Message

Response returns message instance with data

type Logger

type Logger interface {
	Printf(format string, v ...interface{})
}

Logger is a interface to inject a custom logger

type Message

type Message struct {
	Code byte
	Data []byte
}

Message represents a command sent from milter client

type Milter

type Milter interface {
	// Called when milter session is created
	NewSession(logger Logger)

	// Connect is called to provide SMTP connection data for incoming message
	//   supress with NoConnect
	Connect(host string, family string, port uint16, addr net.IP, m *Modifier) (Response, error)

	// Called when we have a new message, can occur more than once per session
	NewMessage()

	// Called when we get RSET, usually an appopriate time to invaliate message-specific state
	Reset()

	// Helo is called to process any HELO/EHLO related filters
	//   supress with NoHelo
	Helo(name string, m *Modifier) (Response, error)

	// MailFrom is called to process filters on envelope FROM address
	//   supress with NoMailForm
	MailFrom(from string, m *Modifier) (Response, error)

	// RcptTo is called to process filters on envelope TO address
	//   supress with NoRcptTo
	RcptTo(rcptTo string, m *Modifier) (Response, error)

	// Header is called once for each header in incoming message
	//   supress with NoHeaders
	Header(name string, value string, m *Modifier) (Response, error)

	// Headers is called when all message headers have been processed
	//   supress with NoHeaders
	Headers(h textproto.MIMEHeader, m *Modifier) (Response, error)

	// BodyChunk is called to process next message body chunk data (up to 64KB in size)
	//   supress with NoBody
	BodyChunk(chunk []byte, m *Modifier) (Response, error)

	// Body is called at the end of each message
	//   all changes to message's content & attributes must be done here
	Body(m *Modifier) (Response, error)

	// EndSession is called at the end of the message Handling loop
	EndSession()
}

Milter is an interface for milter callback handlers

type MilterInit

type MilterInit func() (Milter, OptAction, OptProtocol)

MilterInit initializes milter options multiple options can be set using a bitmask

type Modifier

type Modifier struct {
	Macros  map[string]string
	Headers textproto.MIMEHeader
	// contains filtered or unexported fields
}

Modifier provides access to Macros, Headers and Body data to callback handlers. It also defines a number of functions that can be used by callback handlers to modify processing of the email message

func (*Modifier) AddHeader

func (m *Modifier) AddHeader(name, value string) error

AddHeader appends a new email message header the message

func (*Modifier) AddRecipient

func (m *Modifier) AddRecipient(r string) error

AddRecipient appends a new envelope recipient for current message

func (*Modifier) ChangeFrom

func (m *Modifier) ChangeFrom(value string) error

ChangeFrom replaces the FROM envelope header with a new one

func (*Modifier) ChangeHeader

func (m *Modifier) ChangeHeader(index int, name, value string) error

ChangeHeader replaces the header at the specified position with a new one

func (*Modifier) DeleteRecipient

func (m *Modifier) DeleteRecipient(r string) error

DeleteRecipient removes an envelope recipient address from message

func (*Modifier) InsertHeader

func (m *Modifier) InsertHeader(index int, name, value string) error

InsertHeader inserts the header at the pecified position

func (*Modifier) Quarantine

func (m *Modifier) Quarantine(reason string) error

Quarantine a message by giving a reason to hold it

func (*Modifier) ReplaceBody

func (m *Modifier) ReplaceBody(body []byte) error

ReplaceBody substitutes message body with provided body

type OptAction

type OptAction uint32

OptAction sets which actions the milter wants to perform. Multiple options can be set using a bitmask.

type OptProtocol

type OptProtocol uint32

OptProtocol masks out unwanted parts of the SMTP transaction. Multiple options can be set using a bitmask.

type Response

type Response interface {
	Response() *Message
	Continue() bool
}

Response represents a response structure returned by callback handlers to indicate how the milter server should proceed

type Server

type Server struct {
	Listener      net.Listener
	MilterFactory MilterInit
	ErrHandlers   []func(error)
	Logger        Logger
	sync.WaitGroup
}

Server Milter for handling and processing incoming connections support panic handling via ErrHandler couple of func(error) could be provided for handling error

func (*Server) Close

func (s *Server) Close() (err error)

Close for graceful shutdown Stop accepting new connections And wait until processing connections ends

func (*Server) RunServer

func (s *Server) RunServer() error

RunServer starts milter server via provided listener

type SimpleResponse

type SimpleResponse byte

SimpleResponse type to define list of pre-defined responses

func (SimpleResponse) Continue

func (r SimpleResponse) Continue() bool

Continue to process milter messages only if current code is Continue

func (SimpleResponse) Response

func (r SimpleResponse) Response() *Message

Response returns a Message object reference

Jump to

Keyboard shortcuts

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