Documentation ¶
Index ¶
- Constants
- Variables
- func Compress(stringArguments ...string) string
- func Log() log.Logger
- func MD5Hex(stringArguments ...string) string
- func ParseHeaders(mailData string) map[string]string
- type Backend
- type BackendConfig
- type BackendGateway
- func (gw *BackendGateway) Initialize(cfg BackendConfig) error
- func (gw *BackendGateway) Process(e *mail.Envelope) Result
- func (gw *BackendGateway) Reinitialize() error
- func (gw *BackendGateway) Shutdown() error
- func (gw *BackendGateway) Start() error
- func (gw *BackendGateway) ValidateRcpt(e *mail.Envelope) RcptError
- type BaseConfig
- type DataCompressor
- type Decorator
- type DefaultProcessor
- type Errors
- type GatewayConfig
- type GuerrillaDBAndRedisBackend
- type HeaderConfig
- type InitializeWith
- type NoopProcessor
- type ProcessWith
- type Processor
- type ProcessorConstructor
- type RcptError
- type RedisConn
- type RedisDialOption
- type RedisMockConn
- type RedisProcessor
- type RedisProcessorConfig
- type Result
- type SQLProcessor
- type SQLProcessorConfig
- type SelectTask
- type ShutdownWith
Constants ¶
const ( BackendStateNew backendState = iota BackendStateRunning BackendStateShuttered BackendStateError BackendStateInitialized )
possible values for state
const GuerrillaDBAndRedisBatchMax = 50
how many rows to batch at a time
const GuerrillaDBAndRedisBatchTimeout = time.Second * 3
tick on every...
Variables ¶
var ( NoSuchUser = RcptError(errors.New("no such user")) StorageNotAvailable = RcptError(errors.New("storage not available")) StorageTooBusy = RcptError(errors.New("storage too busy")) StorageTimeout = RcptError(errors.New("storage timeout")) QuotaExceeded = RcptError(errors.New("quota exceeded")) UserSuspended = RcptError(errors.New("user suspended")) StorageError = RcptError(errors.New("storage error")) )
var BackendResultOK = NewResult("200 OK")
var ErrProcessorNotFound error
var RedisDialer redisDial
var (
Svc *service
)
Functions ¶
func Log ¶
Get loads the log.logger in an atomic operation. Returns a stderr logger if not able to load
func ParseHeaders ¶
ParseHeaders is deprecated, see mail.Envelope.ParseHeaders instead
Types ¶
type Backend ¶
type Backend interface { // Process processes then saves the mail envelope Process(*mail.Envelope) Result // ValidateRcpt validates the last recipient that was pushed to the mail envelope ValidateRcpt(e *mail.Envelope) RcptError // Initializes the backend, eg. creates folders, sets-up database connections Initialize(BackendConfig) error // Initializes the backend after it was Shutdown() Reinitialize() error // Shutdown frees / closes anything created during initializations Shutdown() error // Start Starts a backend that has been initialized Start() error }
Backends process received mail. Depending on the implementation, they can store mail in the database, write to a file, check for spam, re-transmit to another server, etc. Must return an SMTP message (i.e. "250 OK") and a boolean indicating whether the message was processed successfully.
type BackendConfig ¶
type BackendConfig map[string]interface{}
type BackendGateway ¶
type BackendGateway struct { // controls access to state sync.Mutex State backendState // contains filtered or unexported fields }
A backend gateway is a proxy that implements the Backend interface. It is used to start multiple goroutine workers for saving mail, and then distribute email saving to the workers via a channel. Shutting down via Shutdown() will stop all workers. The rest of this program always talks to the backend via this gateway.
func (*BackendGateway) Initialize ¶
func (gw *BackendGateway) Initialize(cfg BackendConfig) error
Initialize builds the workers and initializes each one
func (*BackendGateway) Process ¶
func (gw *BackendGateway) Process(e *mail.Envelope) Result
Process distributes an envelope to one of the backend workers with a TaskSaveMail task
func (*BackendGateway) Reinitialize ¶
func (gw *BackendGateway) Reinitialize() error
Reinitialize initializes the gateway with the existing config after it was shutdown
func (*BackendGateway) Shutdown ¶
func (gw *BackendGateway) Shutdown() error
Shutdown shuts down the backend and leaves it in BackendStateShuttered state
func (*BackendGateway) Start ¶
func (gw *BackendGateway) Start() error
Start starts the worker goroutines, assuming it has been initialized or shuttered before
func (*BackendGateway) ValidateRcpt ¶
func (gw *BackendGateway) ValidateRcpt(e *mail.Envelope) RcptError
ValidateRcpt asks one of the workers to validate the recipient Only the last recipient appended to e.RcptTo will be validated.
type DataCompressor ¶
type DataCompressor struct { ExtraHeaders []byte Data *bytes.Buffer // the pool is used to recycle buffers to ease up on the garbage collector Pool *sync.Pool }
compressedData struct will be compressed using zlib when printed via fmt
func (*DataCompressor) String ¶
func (c *DataCompressor) String() string
String implements the Stringer interface. Can only be called once! This is because the compression buffer will be reset and compressor will be returned to the pool
type Decorator ¶
We define what a decorator to our processor will look like
func Compressor ¶
func Compressor() Decorator
func GuerrillaDbRedis ¶
func GuerrillaDbRedis() Decorator
GuerrillaDbRedis is a specialized processor for Guerrilla mail. It is here as an example. It's an example of a 'monolithic' processor.
func Hasher ¶
func Hasher() Decorator
The hasher decorator computes a hash of the email for each recipient It appends the hashes to envelope's Hashes slice.
func Header ¶
func Header() Decorator
Generate the MTA delivery header Sets e.DeliveryHeader part of the envelope with the generated header
func HeadersParser ¶
func HeadersParser() Decorator
type DefaultProcessor ¶
type DefaultProcessor struct{}
DefaultProcessor is a undecorated worker that does nothing Notice DefaultProcessor has no knowledge of the other decorators that have orthogonal concerns.
func (DefaultProcessor) Process ¶
func (w DefaultProcessor) Process(e *mail.Envelope, task SelectTask) (Result, error)
do nothing except return the result (this is the last call in the decorator stack, if it got here, then all is good)
type GatewayConfig ¶
type GatewayConfig struct { // WorkersSize controls how many concurrent workers to start. Defaults to 1 WorkersSize int `json:"save_workers_size,omitempty"` // SaveProcess controls which processors to chain in a stack for saving email tasks SaveProcess string `json:"save_process,omitempty"` // ValidateProcess is like ProcessorStack, but for recipient validation tasks ValidateProcess string `json:"validate_process,omitempty"` // TimeoutSave is duration before timeout when saving an email, eg "29s" TimeoutSave string `json:"gw_save_timeout,omitempty"` // TimeoutValidateRcpt duration before timeout when validating a recipient, eg "1s" TimeoutValidateRcpt string `json:"gw_val_rcpt_timeout,omitempty"` }
type GuerrillaDBAndRedisBackend ¶
type GuerrillaDBAndRedisBackend struct {
// contains filtered or unexported fields
}
type HeaderConfig ¶
type HeaderConfig struct {
PrimaryHost string `json:"primary_mail_host"`
}
type InitializeWith ¶
type InitializeWith func(backendConfig BackendConfig) error
func (InitializeWith) Initialize ¶
func (i InitializeWith) Initialize(backendConfig BackendConfig) error
Satisfy ProcessorInitializer interface So we can now pass an anonymous function that implements ProcessorInitializer
type NoopProcessor ¶
type NoopProcessor struct{ DefaultProcessor }
if no processors specified, skip operation
type ProcessWith ¶
type ProcessWith func(*mail.Envelope, SelectTask) (Result, error)
Signature of Processor
func (ProcessWith) Process ¶
func (f ProcessWith) Process(e *mail.Envelope, task SelectTask) (Result, error)
Make ProcessWith will satisfy the Processor interface
type Processor ¶
type Processor interface {
Process(*mail.Envelope, SelectTask) (Result, error)
}
Our processor is defined as something that processes the envelope and returns a result and error
type ProcessorConstructor ¶
type ProcessorConstructor func() Decorator
type RedisConn ¶
type RedisConn interface { Close() error Do(commandName string, args ...interface{}) (reply interface{}, err error) }
RedisConn interface provides a generic way to access Redis via drivers
type RedisDialOption ¶
type RedisDialOption struct {
// contains filtered or unexported fields
}
type RedisMockConn ¶
type RedisMockConn struct{}
func (*RedisMockConn) Close ¶
func (m *RedisMockConn) Close() error
func (*RedisMockConn) Do ¶
func (m *RedisMockConn) Do(commandName string, args ...interface{}) (reply interface{}, err error)
type RedisProcessor ¶
type RedisProcessor struct {
// contains filtered or unexported fields
}
type RedisProcessorConfig ¶
type Result ¶
type Result interface { fmt.Stringer // Code should return the SMTP code associated with this response, ie. `250` Code() int }
Result represents a response to an SMTP client after receiving DATA. The String method should return an SMTP message ready to send back to the client, for example `250 OK: Message received`.
type SQLProcessor ¶
type SQLProcessor struct {
// contains filtered or unexported fields
}
type SQLProcessorConfig ¶
type SQLProcessorConfig struct { Table string `json:"mail_table"` Driver string `json:"sql_driver"` DSN string `json:"sql_dsn"` SQLInsert string `json:"sql_insert,omitempty"` SQLValues string `json:"sql_values,omitempty"` PrimaryHost string `json:"primary_mail_host"` MaxConnLifetime string `json:"sql_max_conn_lifetime,omitempty"` MaxOpenConns int `json:"sql_max_open_conns,omitempty"` MaxIdleConns int `json:"sql_max_idle_conns,omitempty"` }
type SelectTask ¶
type SelectTask int
const ( TaskSaveMail SelectTask = iota TaskValidateRcpt )
func (SelectTask) String ¶
func (o SelectTask) String() string
type ShutdownWith ¶
type ShutdownWith func() error
func (ShutdownWith) Shutdown ¶
func (s ShutdownWith) Shutdown() error
satisfy ProcessorShutdowner interface, same concept as InitializeWith type