msmtpd

package module
v1.3.0 Latest Latest
Warning

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

Go to latest
Published: Jan 24, 2024 License: MIT Imports: 25 Imported by: 0

README

msmtpd

PkgGoDev Go Report Card Go

Golang framework for building Simple Mail Transfer Protocol Daemons.

Фреймворк для создания почтовых серверов, написанный на Go.

Mirrors

Main features

  1. Haraka hooks inspired CheckerFunc's being called on different actions of client (connection, HELO/EHLO command, StartTLS)
  2. StartTLS, XClient, Proxy command support
  3. Easy to implement logger interface
  4. Build-in OpenTelemetry support - see dovecot_inbound and dovecot_outbound examples
  5. Lot of plugins, including:
  6. Dovecot plugin for authentication and LMTP mail delivery
  7. Rspamd plugin for blocking spam
  8. Plugins to deliver via 3rd party SMTP proxy, LMTP and SendMail.
  9. Experimental Karma plugin to implement connection scoring (IP addresses making failed SMTP transactions will be blacklisted)
  10. HELO/EHLO checkers, including complicated ones
  11. Sender resolvable checker plugin to ensure sender's domain can accept our replies

Examples / Примеры

Inspiration / Источники вдохновения

Minimal example / Минимальный пример


package main

import (
	"log"

	"github.com/vodolaz095/msmtpd"
)

func main() {
	server := msmtpd.Server{
		Hostname:       "localhost",
		WelcomeMessage: "Do you believe in our God?",
	}

	err := server.ListenAndServe(":1025")
	if err != nil {
		log.Fatalf("%s : while starting server on 0.0.0.0:1025", err)
	}
}


Server log / Протокол работы сервера

2023/08/02 16:30:11 INFO [1cca484c18ebe494240b196bc60ee39c]: Accepting connection from [::1]:34142...
2023/08/02 16:30:11 INFO [1cca484c18ebe494240b196bc60ee39c]: EHLO <localhost> is accepted!
2023/08/02 16:30:11 INFO [1cca484c18ebe494240b196bc60ee39c]: MAIL FROM <sender@example.org> is checked by 0
SenderCheckers and accepted!
2023/08/02 16:30:11 INFO [1cca484c18ebe494240b196bc60ee39c]: Recipient <recipient@example.org> will be 1st one in
transaction!
2023/08/02 16:30:11 INFO [1cca484c18ebe494240b196bc60ee39c]: Subject: test Wed, 02 Aug 2023 16:30:11 +0300
2023/08/02 16:30:11 INFO [1cca484c18ebe494240b196bc60ee39c]: Body (264 bytes) checked by 0 DataCheckers successfully!
2023/08/02 16:30:11 WARN [1cca484c18ebe494240b196bc60ee39c]: Message silently discarded - no DataHandlers set...
2023/08/02 16:30:12 INFO [1cca484c18ebe494240b196bc60ee39c]: Closing transaction.
2023/08/02 16:30:31 INFO [4dfe768e04186309306b1af3194b05c4]: Accepting connection from [::1]:50596...
2023/08/02 16:30:31 INFO [4dfe768e04186309306b1af3194b05c4]: EHLO <localhost> is accepted!
2023/08/02 16:30:31 INFO [4dfe768e04186309306b1af3194b05c4]: MAIL FROM <sender@example.org> is checked by 0
SenderCheckers and accepted!
2023/08/02 16:30:31 INFO [4dfe768e04186309306b1af3194b05c4]: Recipient <recipient1@example.org> will be 1st one in
transaction!
2023/08/02 16:30:31 INFO [4dfe768e04186309306b1af3194b05c4]: Recipient <recipient2@example.org> will be 2nd one in
transaction!
2023/08/02 16:30:31 INFO [4dfe768e04186309306b1af3194b05c4]: Recipient <recipient3@example.org> will be 2nd one in
transaction!
2023/08/02 16:30:31 INFO [4dfe768e04186309306b1af3194b05c4]: Recipient <recipient4@example.org> will be 4th one in
transaction!
2023/08/02 16:30:31 INFO [4dfe768e04186309306b1af3194b05c4]: Subject: test Wed, 02 Aug 2023 16:30:31 +0300
2023/08/02 16:30:31 INFO [4dfe768e04186309306b1af3194b05c4]: Body (334 bytes) checked by 0 DataCheckers successfully!
2023/08/02 16:30:31 WARN [4dfe768e04186309306b1af3194b05c4]: Message silently discarded - no DataHandlers set...
2023/08/02 16:30:31 INFO [4dfe768e04186309306b1af3194b05c4]: Closing transaction.

Client log while testing smtp server / Вывод клиента при тестировании почтового сервера

$ swaks --to recipient1@example.org,recipient2@example.org,recipient3@example.org,recipient4@example.org \
    --from sender@example.org \
    --server localhost --port 1025 \
    --timeout 600
=== Trying localhost:1025...
=== Connected to localhost.
<- 220 Do you believe in our God?
-> EHLO localhost
<- 250-localhost
<- 250-SIZE 10240000
<- 250-8BITMIME
<- 250 PIPELINING
-> MAIL FROM:<sender@example.org>
<- 250 Ok, it makes sense, go ahead please!
-> RCPT TO:<recipient1@example.org>
<- 250 It seems i can handle delivery for this recipient, i'll do my best!
-> RCPT TO:<recipient2@example.org>
<- 250 It seems i can handle delivery for this recipient, i'll do my best!
-> RCPT TO:<recipient3@example.org>
<- 250 It seems i can handle delivery for this recipient, i'll do my best!
-> RCPT TO:<recipient4@example.org>
<- 250 It seems i can handle delivery for this recipient, i'll do my best!
-> DATA
<- 354 Ok, you managed to talk me into accepting your message. Go on, end your data with <CR><LF>.<CR><LF>
-> Date: Wed, 02 Aug 2023 16:30:31 +0300
-> To: recipient1@example.org,recipient2@example.org,recipient3@example.org,recipient4@example.org
-> From: sender@example.org
-> Subject: test Wed, 02 Aug 2023 16:30:31 +0300
-> Message-Id: <20230802163031.059039@localhost>
-> X-Mailer: swaks v20190914.0 jetmore.org/john/code/swaks/
->
-> This is a test mailing
->
->
-> .
<- 250 Thank you.
-> QUIT
<- 221 Farewell, my friend! Transaction 4dfe768e04186309306b1af3194b05c4 is finished

Support development / Поддержать разработку

https://www.tinkoff.ru/rm/ostroumov.anatoliy2/4HFzm76801/

Documentation

Overview

Package msmtpd is framework for building Enchanced/Simple Mail Transfer Protocol daemons including inbound, outbound servers, smtp proxies, spamtraps, honeypots and everything that talks SMTP

Example
// set main server context
ctx, cancel := context.WithCancel(context.TODO())
defer cancel()

// configure logger
logger := DefaultLogger{
	Logger: log.Default(),
	Level:  TraceLevel,
}
// configure server
server := Server{
	Hostname:       "mx.example.org",
	WelcomeMessage: "mx.example.org ESMTP ready.",

	// limits
	ReadTimeout:    time.Minute,
	WriteTimeout:   time.Minute,
	DataTimeout:    3 * time.Minute,
	MaxConnections: 10,
	MaxMessageSize: 32 * 1024 * 1014, // 32 Mbytes
	MaxRecipients:  10,
	// you can configure DNS resolver being used for application
	Resolver: net.DefaultResolver,
	// can make things faster, but various HELO/EHLO checks will not work
	SkipResolvingPTR: false,
	// enable xclient extension, use with care! https://www.postfix.org/XCLIENT_README.html
	EnableXCLIENT: false,
	// enable proxy support, like Haraka allows for HaProxy https://haraka.github.io/core/HAProxy
	EnableProxyProtocol: false,

	// if you plan to make server listen TLS or use StartTLS command, here
	// you can configure it and require all sensitive data to be transferred via
	// encrypted channel
	TLSConfig: nil,
	ForceTLS:  false,

	// plug your custom logger here
	Logger: &logger,

	// main context of server and its cancel function
	Context: ctx,
	Cancel:  cancel,

	// ConnectionCheckers are called when client performed TCP connection
	ConnectionCheckers: []ConnectionChecker{
		func(tr *Transaction) error {
			tr.LogInfo("Client connects from %s...", tr.Addr.String())
			return nil
		},
	},
	// HeloCheckers are called when client tries to perform HELO/EHLO
	HeloCheckers: []HelloChecker{
		func(tr *Transaction) error {
			tr.LogInfo("Client HELO is %s", tr.HeloName)
			return nil
		},
		func(tr *Transaction) error {
			if tr.HeloName != "localhost" {
				tr.Hate(1) // i do not like being irritated
			} else {
				tr.SetFlag("localhost")
			}
			return nil
		},
	},
	// SenderCheckers are called when client provides MAIL FROM to define who sends email message
	SenderCheckers: []SenderChecker{
		func(tr *Transaction) error {
			tr.LogInfo("Somebody called %s tries to send message...", tr.MailFrom)
			return nil
		},
	},
	// RecipientCheckers are called each time client provides RCPT TO
	// in order to define for whom to send email message
	RecipientCheckers: []RecipientChecker{
		func(tr *Transaction, recipient *mail.Address) error {
			if strings.HasPrefix(recipient.Address, "info@") {
				return ErrorSMTP{
					Code:    535,
					Message: "Just stop it, please",
				}
			}
			return nil
		},
	},
	// DataCheckers are called on message body to ensure it is properly formatted ham email
	// message according to RFC 5322 and RFC 6532.
	DataCheckers: []DataChecker{
		func(tr *Transaction) error {
			if tr.Parsed.Header.Get("X-Priority") == "" {
				return ErrorSMTP{
					Code:    535,
					Message: "Please, provide priority for your message!",
				}
			}
			// Add header to message
			tr.AddHeader("Something", "interesting")
			return nil
		},
	},
	// DataHandlers do actual message delivery to persistent storage
	DataHandlers: []DataHandler{
		func(tr *Transaction) error {
			tr.LogInfo("We pretend we deliver %v bytes of message somehow", len(tr.Body))
			// set float64 fact about transaction
			tr.Incr("size", float64(len(tr.Body)))
			return ErrServiceNotAvailable
		},
	},
	// CloseHandlers are called when client closes connection, they can be used
	// to, for example, record connection data in database or save metrics
	CloseHandlers: []CloseHandler{
		func(tr *Transaction) error {
			tr.LogInfo("Closing connection. Karma is %d", tr.Karma())
			// reading string fact
			subject, found := tr.GetFact(SubjectFact)
			if found {
				tr.LogInfo("Subject %s", subject)
			}
			// reading float64 counter
			size, found := tr.GetCounter("size")
			if found {
				tr.LogInfo("Body size is %v", size)
			}
			// reading boolean flag present
			if tr.IsFlagSet("localhost") {
				tr.LogInfo("Transaction is send from localhost")
			}
			return nil // error means nothing here, to be honest
		},
	},
}
// start http endpoint for metrics scrapping.
// Format explained here: https://prometheus.io/docs/instrumenting/exposition_formats/
go func() {
	pmErr := server.StartPrometheusScrapperEndpoint(":3000", "/metrics")
	if pmErr != nil {
		log.Fatalf("%s : while starting metrics scrapper endpoint", pmErr)
	}
}()
// Actually, start server on 25th port
err := server.ListenAndServe(":25")
if err != nil {
	log.Fatalf("%s : while starting server on %s", err, server.Address())
}
Output:

Index

Examples

Constants

View Source
const SubjectFact = "subject"

SubjectFact is default name for fact key to store message Subject as string

Variables

View Source
var ErrAuthenticationCredentialsInvalid = ErrorSMTP{
	Code:    535,
	Message: "Authentication credentials are invalid.",
}

ErrAuthenticationCredentialsInvalid means SMTP credentials are invalid

View Source
var ErrServerClosed = errors.New("smtp: Server closed")

ErrServerClosed is returned by the Server's Serve and ListenAndServe, methods after a call to shut down.

View Source
var ErrServiceDoesNotAcceptEmail = ErrorSMTP{
	Code:    521,
	Message: "Server does not accept mail. Do not retry delivery, please. It will fail.",
}

ErrServiceDoesNotAcceptEmail means server will not perform this SMTP transaction, even if your try to retry it

View Source
var ErrServiceNotAvailable = ErrorSMTP{
	Code:    421,
	Message: "Service not available. Try again later, please.",
}

ErrServiceNotAvailable means server cannot perform this SMTP transaction and it should be retried later

View Source
var TLSVersions = map[uint16]string{
	tls.VersionSSL30: "SSL3.0",
	tls.VersionTLS10: "TLS1.0",
	tls.VersionTLS11: "TLS1.1",
	tls.VersionTLS12: "TLS1.2",
	tls.VersionTLS13: "TLS1.3",
}

TLSVersions is used to pretty print TLS protocol version being used

Functions

func AuthenticatorForTestsThatAlwaysFails

func AuthenticatorForTestsThatAlwaysFails(tr *Transaction, username, password string) error

AuthenticatorForTestsThatAlwaysFails should not be used for production

func AuthenticatorForTestsThatAlwaysWorks

func AuthenticatorForTestsThatAlwaysWorks(tr *Transaction, username, password string) error

AuthenticatorForTestsThatAlwaysWorks should not be used for production

func RunTestServerWithTLS

func RunTestServerWithTLS(t *testing.T, server *Server) (addr string, closer func())

RunTestServerWithTLS runs test server for unit tests with TLS support and cert for localhost

func RunTestServerWithoutTLS

func RunTestServerWithoutTLS(t *testing.T, server *Server) (addr string, closer func())

RunTestServerWithoutTLS runs test server for unit tests without TLS support

Types

type AuthenticatorFunc

type AuthenticatorFunc func(transaction *Transaction, username, password string) error

AuthenticatorFunc is signature of function used to handle authentication

type CheckerFunc

type CheckerFunc func(transaction *Transaction) error

CheckerFunc are signature of functions used in checks for client issuing HELO/EHLO, MAIL FROM, DATA commands Note that we can store counters and Facts in Transaction, in order to extract and reuse it in the future.

type CloseHandler

type CloseHandler CheckerFunc

CloseHandler is called when server terminates SMTP session, it can be used for, for example, storing Karma or reporting statistics

type ConnectionChecker

type ConnectionChecker CheckerFunc

ConnectionChecker are called when tcp connection are established, if they return non-null error, connection is terminated

type DataChecker

type DataChecker CheckerFunc

DataChecker is called when client provided message body, and we need to ensure it is sane. It is good place to use RSPAMD and other message body validators here

type DataHandler

type DataHandler CheckerFunc

DataHandler is called when client provided message body, it was checked by all DataChecker functions, and we need to deliver message to LMTP or 3rd party SMTP server.

type DefaultLogger

type DefaultLogger struct {
	*log.Logger
	Level LoggerLevel
}

DefaultLogger is logger by default using standard library logger as backend https://pkg.go.dev/log

func (*DefaultLogger) Debugf

func (d *DefaultLogger) Debugf(transaction *Transaction, format string, args ...any)

Debugf sends DebugLevel message

func (*DefaultLogger) Errorf

func (d *DefaultLogger) Errorf(transaction *Transaction, format string, args ...any)

Errorf sends ErrorLevel message

func (*DefaultLogger) Fatalf

func (d *DefaultLogger) Fatalf(transaction *Transaction, format string, args ...any)

Fatalf sends FatalLevel message and stops application with exit code 1

func (*DefaultLogger) Infof

func (d *DefaultLogger) Infof(transaction *Transaction, format string, args ...any)

Infof sends InfoLevel message

func (*DefaultLogger) Tracef

func (d *DefaultLogger) Tracef(transaction *Transaction, format string, args ...any)

Tracef sends TraceLevel message

func (*DefaultLogger) Warnf

func (d *DefaultLogger) Warnf(transaction *Transaction, format string, args ...any)

Warnf sends WarnLevel message

type ErrorSMTP

type ErrorSMTP struct {
	Code    int    // The integer error code
	Message string // The error message
}

ErrorSMTP represents an Error reported in the SMTP session.

func (ErrorSMTP) Error

func (e ErrorSMTP) Error() string

Error returns a string representation of the SMTP error

type HelloChecker

type HelloChecker CheckerFunc

HelloChecker is called after client provided HELO/EHLO greeting, returned errors are send to client as ErrorSMTP responses

type Logger

type Logger interface {
	Tracef(transaction *Transaction, format string, args ...any)
	Debugf(transaction *Transaction, format string, args ...any)
	Infof(transaction *Transaction, format string, args ...any)
	Warnf(transaction *Transaction, format string, args ...any)
	Errorf(transaction *Transaction, format string, args ...any)
	Fatalf(transaction *Transaction, format string, args ...any)
}

Logger is interface all Server loggers must satisfy

type LoggerLevel

type LoggerLevel uint8

LoggerLevel describes logging level like JournalD has by https://github.com/coreos/go-systemd/blob/main/journal/journal.go See for inspiration https://stackoverflow.com/questions/2031163/when-to-use-the-different-log-levels

const DebugLevel LoggerLevel = 7

DebugLevel is used when we log information that is diagnostically helpful to people more than just developers (IT, sysadmins, etc.).

const ErrorLevel LoggerLevel = 3

ErrorLevel is used for any error which is fatal to the operation, but not the service or application (can't open a required file, missing data, etc.). These errors will force user (administrator, or direct user) intervention.

const FatalLevel LoggerLevel = 2

FatalLevel is used for any error that is forcing a shutdown of the service or application to prevent data loss (or further data loss).

const InfoLevel LoggerLevel = 6

InfoLevel is used when we log generally useful information to log (service start/stop, configuration assumptions, etc). This is information we always want to be available but we usually don't care about under normal circumstances. This is my out-of-the-box config level.

const TraceLevel LoggerLevel = 8

TraceLevel is used when we record very verbose message like SMTP protocol raw data being sent/received

const WarnLevel LoggerLevel = 4

WarnLevel is used when we log anything that can potentially cause application oddities, but for which we are automatically recovering. Such as switching from a primary to backup server, retrying an operation, missing secondary data, etc.

func (LoggerLevel) String

func (ll LoggerLevel) String() string

type Protocol

type Protocol string

Protocol represents the protocol used in the SMTP session

const (
	// SMTP means Simple Mail Transfer Protocol
	SMTP Protocol = "SMTP"

	// ESMTP means Extended Simple Mail Transfer Protocol, because it has some extra features
	// Simple Mail Transfer Protocol doesn't have
	ESMTP Protocol = "ESMTP"
)

type RecipientChecker

type RecipientChecker func(transaction *Transaction, recipient *mail.Address) error

RecipientChecker is called for each RCPT TO client provided, if they return null error, recipient is added to Transaction.RcptTo, else returned errors are send to client as ErrorSMTP responses

type SenderChecker

type SenderChecker CheckerFunc

SenderChecker is called after client provided MAIL FROM, returned errors are send // to client as ErrorSMTP responses

type Server

type Server struct {
	// Hostname is how we name ourselves, default is "localhost.localdomain"
	Hostname string
	// WelcomeMessage sets initial server banner. (default: "<hostname> ESMTP ready.")
	WelcomeMessage string
	// ReadTimeout is socket timeout for read operations. (default: 60s)
	ReadTimeout time.Duration
	// WriteTimeout is socket timeout for write operations. (default: 60s)
	WriteTimeout time.Duration
	// DataTimeout Socket timeout for DATA command (default: 5m)
	DataTimeout time.Duration

	// MaxConnections sets maximum number of concurrent connections, use -1 to disable. (default: 100)
	MaxConnections int
	// MaxMessageSize, default is 10240000 bytes
	MaxMessageSize int
	// MaxRecipients are limit for RCPT TO calls for each envelope. (default: 100)
	MaxRecipients int

	// Resolver is net.Resolver used by server and plugins to resolve remote resources against DNS servers
	Resolver *net.Resolver

	// SkipResolvingPTR disables resolving reverse/point DNS records of connecting IP address,
	// it can be useful in various DNS checks, but it reduces performance due to quite
	// expensive and slow DNS calls. By default resolving PTR records is enabled
	SkipResolvingPTR bool

	// ConnectionCheckers are called when TCP connection is started, if any of connection
	// checkers returns error, connection is closed, which is reported as ErrorSMTP being send to
	// client before connection is terminated
	ConnectionCheckers []ConnectionChecker

	// HeloCheckers are called after client send HELO/EHLO commands
	// If any of HeloCheckers returns error, it will be reported as HELO/EHLO command response,
	// and HELO command will be considered erroneous.
	HeloCheckers []HelloChecker

	// SenderCheckers are called when client issues MAIL FROM command
	// If any of SenderCheckers returns error, it will be reported as MAIL FROM command response,
	// and command will be considered erroneous.
	SenderCheckers []SenderChecker

	// RecipientCheckers are called every time client issues RCPT TO command
	// 1st argument is Transaction, 2nd one - RCPT TO payload
	// If any of RecipientCheckers returns error, it will be reported as RCPT TO command response
	// and command will be considered erroneous.
	RecipientCheckers []RecipientChecker

	// Authenticator, while being not nil, enables PLAIN/LOGIN authentication,
	// only available after STARTTLS. Variable can be left empty for no authentication support.
	// If Authenticator returns error, authentication will be considered erroneous.
	Authenticator func(transaction *Transaction, username, password string) error

	// DataCheckers are functions called to check message body before passing it
	// to DataHandlers for delivery. If left empty, body is not checked. It is worth
	// mentioning that message body is parsed according to RFC 5322 to ensure mandatory
	// headers From and Date are present, and important ones do not have duplicates.
	// If any of data checkers returns error, it will be reported as DATA
	// command response and command will be considered erroneous.
	DataCheckers []DataChecker

	// DataHandlers are functions to process message body after DATA command.
	// Can be left empty for a NOOP server.
	// If any of DataHandlers returns error, it will be reported as DATA
	// command response and command will be considered erroneous.
	DataHandlers []DataHandler

	// CloseHandlers are called after connection is closed. They can be used to, for example,
	// update counters, save connection metadata into persistent storage like Karma plugin does,
	// or it can even issue shell command to blacklist remote IP by firewall
	CloseHandlers []CloseHandler

	// EnableXCLIENT enables XClient command support (disabled by default, since it is security risk)
	EnableXCLIENT bool
	// EnableProxyProtocol enables Proxy command support (disabled by default, since it is security risk)
	EnableProxyProtocol bool
	// HideTransactionHeader hides transaction header
	HideTransactionHeader bool
	// TLSConfig is used both for STARTTLS and operation over TLS channel
	TLSConfig *tls.Config
	// ForceTLS requires connections to be encrypted
	ForceTLS bool
	// Logger is interface being used as protocol/plugin/errors logger
	Logger Logger
	// Tracer is OpenTelemetry tracer which starts spans for every Transaction
	Tracer trace.Tracer

	// Context is main context in which server is started
	Context context.Context
	// Cancel cancels main server Context
	Cancel context.CancelFunc
	// contains filtered or unexported fields
}

Server defines the parameters for running the SMTP server

func (*Server) Address

func (srv *Server) Address() net.Addr

Address returns the listening address of the server

func (*Server) GetActiveTransactionsCount

func (srv *Server) GetActiveTransactionsCount() int32

GetActiveTransactionsCount returns number of active transactions this server is processing

func (*Server) GetBytesRead

func (srv *Server) GetBytesRead() uint64

GetBytesRead returns number of bytes written

func (*Server) GetBytesWritten

func (srv *Server) GetBytesWritten() uint64

GetBytesWritten returns number of bytes written

func (*Server) GetFailedTransactionsCount added in v1.1.0

func (srv *Server) GetFailedTransactionsCount() uint64

GetFailedTransactionsCount returns number of failed transactions this server processed

func (*Server) GetSuccessfulTransactionsCount added in v1.1.0

func (srv *Server) GetSuccessfulTransactionsCount() uint64

GetSuccessfulTransactionsCount returns number of successful transactions this server processed

func (*Server) GetTransactionsCount

func (srv *Server) GetTransactionsCount() uint64

GetTransactionsCount returns number of all transactions this server processed

func (*Server) ListenAndServe

func (srv *Server) ListenAndServe(addr string) error

ListenAndServe starts the SMTP server and listens on the address provided

func (*Server) ResetCounters

func (srv *Server) ResetCounters()

ResetCounters resets counters

func (*Server) Serve

func (srv *Server) Serve(l net.Listener) error

Serve starts the SMTP server and listens on the Listener provided

func (*Server) Shutdown

func (srv *Server) Shutdown(wait bool) error

Shutdown instructs the server to shut down, starting by closing the associated listener. If wait is true, it will wait for the shutdown to complete. If wait is false, Wait must be called afterwards.

func (*Server) StartPrometheusScrapperEndpoint

func (srv *Server) StartPrometheusScrapperEndpoint(address, path string) (err error)

StartPrometheusScrapperEndpoint starts prometheus scrapper endpoint with data in this format https://prometheus.io/docs/instrumenting/exposition_formats/

func (*Server) Wait

func (srv *Server) Wait() error

Wait waits for all client connections to close and the server to finish shutting down.

type TestLogger

type TestLogger struct {
	Suite *testing.T
}

TestLogger is logger being used only in unit tests

func (*TestLogger) Debugf

func (tl *TestLogger) Debugf(transaction *Transaction, format string, args ...any)

Debugf records debug level message

func (*TestLogger) Errorf

func (tl *TestLogger) Errorf(transaction *Transaction, format string, args ...any)

Errorf records error level message

func (*TestLogger) Fatalf

func (tl *TestLogger) Fatalf(transaction *Transaction, format string, args ...any)

Fatalf records fatal level message and fails test

func (*TestLogger) Infof

func (tl *TestLogger) Infof(transaction *Transaction, format string, args ...any)

Infof records info level message

func (*TestLogger) Tracef

func (tl *TestLogger) Tracef(transaction *Transaction, format string, args ...any)

Tracef records trace level message

func (*TestLogger) Warnf

func (tl *TestLogger) Warnf(transaction *Transaction, format string, args ...any)

Warnf records warning level message

type Transaction

type Transaction struct {
	// ID is unique transaction identificator
	ID string `json:"id"`
	// StartedAt depicts moment when transaction was initiated
	StartedAt time.Time

	// ServerName depicts how out smtp server names itself
	ServerName string
	// Addr depicts network address of remote client
	Addr net.Addr
	// PTRs are  DNS PTR record is exactly the opposite of the 'A' record, which provides the IP address associated with a
	// domain name.
	PTRs []string

	// TLS Connection details, if encryption is enabled
	// Ptrs are DNS pointer record which provides the domain name associated with an IP address.
	TLS *tls.ConnectionState
	// Encrypted means connection is encrypted by TLS
	Encrypted bool
	// Secured means TLS handshake succeeded
	Secured bool

	// Logger is logging system inherited from server
	Logger Logger

	// HeloName is how client introduced himself via HELO/EHLO command
	HeloName string
	// Protocol used, SMTP or ESMTP
	Protocol Protocol
	// Username as provided by via authorization process command
	Username string
	// Password from authentication, if authenticated
	Password string
	// MailFrom stores address from which this message is originated as client says via `MAIL FROM:`
	MailFrom mail.Address
	// RcptTo stores addresses for which this message should be delivered as client says via `RCPT TO:`
	RcptTo []mail.Address

	// Body stores unparsed message body
	Body []byte
	// Parsed stores parsed message body
	Parsed *mail.Message

	// Aliases are actual users addresses used by delivery plugins
	Aliases []mail.Address

	// Span is OpenTelemetry span being used in transaction
	Span trace.Span
	// contains filtered or unexported fields
}

Transaction used to handle all SMTP protocol interactions with client

func (*Transaction) AddHeader

func (t *Transaction) AddHeader(name, value string)

AddHeader adds header to the Transaction.Parsed, and to the Transaction.Body, so, it should be called before AddReceivedLine, since it adds header to the top

func (*Transaction) AddReceivedLine

func (t *Transaction) AddReceivedLine()

AddReceivedLine prepends a Received header to the Transaction.Body

func (*Transaction) Context

func (t *Transaction) Context() context.Context

Context returns transaction context, which is canceled when transaction is closed

func (*Transaction) GetCounter

func (t *Transaction) GetCounter(key string) (val float64, found bool)

GetCounter returns counter value

func (*Transaction) GetFact

func (t *Transaction) GetFact(name string) (value string, found bool)

GetFact returns string fact from Transaction.facts

func (*Transaction) Hate

func (t *Transaction) Hate(delta int) (newVal int)

Hate grants bad points to karma, restricting message to enter Paradise for SMTP transactions, aka dovecot server socket for accepting messages via SMTP

func (*Transaction) Incr

func (t *Transaction) Incr(key string, delta float64) (newVal float64)

Incr increments transaction counter

func (*Transaction) IsFlagSet

func (t *Transaction) IsFlagSet(name string) bool

IsFlagSet returns true, if flag is set

func (*Transaction) Karma

func (t *Transaction) Karma() int

Karma returns current transaction karma

func (*Transaction) LogDebug

func (t *Transaction) LogDebug(format string, args ...any)

LogDebug is used to send debug level message to server logger

func (*Transaction) LogError

func (t *Transaction) LogError(err error, desc string)

LogError is used to send error level message to server logger. This function marks OpenTelemetry Transaction's span as erroneous one

func (*Transaction) LogFatal

func (t *Transaction) LogFatal(err error, desc string)

LogFatal is used to send error level message to server logger

func (*Transaction) LogInfo

func (t *Transaction) LogInfo(format string, args ...any)

LogInfo is used to send info level message to server logger

func (*Transaction) LogTrace

func (t *Transaction) LogTrace(format string, args ...any)

LogTrace is used to send trace level message to server logger

func (*Transaction) LogWarn

func (t *Transaction) LogWarn(format string, args ...any)

LogWarn is used to send warning level message to server logger

func (*Transaction) Love

func (t *Transaction) Love(delta int) (newVal int)

Love grants good points to karma, promising message to enter Paradise for SMTP transactions, aka dovecot server socket for accepting messages via SMTP

func (*Transaction) Resolver

func (t *Transaction) Resolver() *net.Resolver

Resolver returns net.Resolver being used for this transaction

func (*Transaction) SetFact

func (t *Transaction) SetFact(name, value string)

SetFact sets string parameter Transaction.facts

func (*Transaction) SetFlag

func (t *Transaction) SetFlag(name string)

SetFlag set flag enabled for transaction

func (*Transaction) UnsetFlag

func (t *Transaction) UnsetFlag(name string)

UnsetFlag unsets boolean flag from transaction

Directories

Path Synopsis
example
plugins
dovecot
Package dovecot implements functions to interact with Dovecot's authentication service.
Package dovecot implements functions to interact with Dovecot's authentication service.

Jump to

Keyboard shortcuts

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