Documentation
¶
Index ¶
- Constants
- Variables
- type Backend
- type BackendFunc
- type Conn
- func (c *Conn) Close(err error)
- func (c *Conn) Conn() net.Conn
- func (c *Conn) Hostname() string
- func (c *Conn) IsTLS() bool
- func (c *Conn) Mechanisms() []string
- func (c *Conn) Reject(ctx context.Context)
- func (c *Conn) Server() *Server
- func (c *Conn) TLSConnectionState() (state tls.ConnectionState, ok bool)
- type Option
- func WithAddr(addr string) Option
- func WithBackend(backend Backend) Option
- func WithEnableBINARYMIME(enableBINARYMIME bool) Option
- func WithEnableCHUNKING(enableCHUNKING bool) Option
- func WithEnableDSN(enableDSN bool) Option
- func WithEnableREQUIRETLS(enableREQUIRETLS bool) Option
- func WithEnableSMTPUTF8(enableSMTPUTF8 bool) Option
- func WithEnableXOORG(enableXOORG bool) Option
- func WithEnforceAuthentication(enforceAuthentication bool) Option
- func WithEnforceSecureConnection(enforceSecureConnection bool) Option
- func WithHostname(hostname string) Option
- func WithImplicitTLS(implicitTLS bool) Option
- func WithLogger(logger *slog.Logger) Option
- func WithMaxLineLength(maxLineLength int) Option
- func WithMaxMessageBytes(maxMessageBytes int64) Option
- func WithMaxRecipients(maxRecipients int) Option
- func WithNetwork(network string) Option
- func WithReadTimeout(readTimeout time.Duration) Option
- func WithReaderSize(readerSize int) Option
- func WithTLSConfig(tlsConfig *tls.Config) Option
- func WithWriteTimeout(writeTimeout time.Duration) Option
- func WithWriterSize(writerSize int) Option
- type Server
- func (s *Server) Address() string
- func (s *Server) Backend() Backend
- func (s *Server) Close(ctx context.Context) error
- func (s *Server) Listen(ctx context.Context) (net.Listener, error)
- func (s *Server) ListenAndServe(ctx context.Context) error
- func (s *Server) Serve(ctx context.Context, l net.Listener) error
- func (s *Server) Shutdown(ctx context.Context) error
- type Session
Examples ¶
Constants ¶
const ( StateInit = iota StateUpgrade StateEnforceAuthentication StateEnforceSecureConnection StateGreeted StateMail )
Variables ¶
var ErrServerClosed = errors.New("smtp: server already closed")
Functions ¶
This section is empty.
Types ¶
type Backend ¶
type Backend interface {
NewSession(ctx context.Context, c *Conn) (context.Context, Session, error)
}
A SMTP server backend.
type BackendFunc ¶
BackendFunc is an adapter to allow the use of an ordinary function as a Backend.
func (BackendFunc) NewSession ¶
NewSession calls f(c). The returning context is used in the session.
type Conn ¶
type Conn struct {
// contains filtered or unexported fields
}
func (*Conn) Mechanisms ¶ added in v0.0.7
func (*Conn) TLSConnectionState ¶
func (c *Conn) TLSConnectionState() (state tls.ConnectionState, ok bool)
TLSConnectionState returns the connection's TLS connection state. Zero values are returned if the connection doesn't use TLS.
type Option ¶
type Option func(*Server)
Option is an option for the server.
func WithEnableBINARYMIME ¶
WithEnableBINARYMIME sets EnableBINARYMIME.
func WithEnableCHUNKING ¶
WithEnableCHUNKING sets EnableCHUNKING.
func WithEnableREQUIRETLS ¶
WithEnableREQUIRETLS sets EnableREQUIRETLS.
func WithEnableSMTPUTF8 ¶
WithEnableSMTPUTF8 sets EnableSMTPUTF8.
func WithEnforceAuthentication ¶
WithEnforceAuthentication enforces authentication before mail usage.
func WithEnforceSecureConnection ¶
WithEnforceSecureConnection enforces implicit TLS or STARTTLS.
func WithImplicitTLS ¶
WithImplicitTLS sets implicitTLS.
func WithMaxLineLength ¶
WithMaxLineLength sets the max length per line.
func WithMaxMessageBytes ¶
WithMaxMessageBytes sets the max message size.
func WithMaxRecipients ¶
WithMaxRecipients sets the max recipients per mail.
func WithReadTimeout ¶
WithReadTimeout sets the read timeout.
func WithTLSConfig ¶
WithTLSConfig sets certificate.
func WithWriteTimeout ¶
WithWriteTimeout sets the write timeout.
type Server ¶
type Server struct {
// contains filtered or unexported fields
}
A SMTP server.
Example ¶
ExampleServer runs an example SMTP server.
It can be tested manually with e.g. netcat:
> netcat -C localhost 1025 EHLO localhost AUTH PLAIN AHVzZXJuYW1lAHBhc3N3b3Jk MAIL FROM:<root@nsa.gov> RCPT TO:<root@gchq.gov.uk> DATA Hey <3 .
package main import ( "context" "crypto/tls" "errors" "io" "log" "log/slog" "time" "github.com/uponusolutions/go-sasl" "github.com/uponusolutions/go-smtp" "github.com/uponusolutions/go-smtp/server" ) // The Backend implements SMTP server methods. type Backend struct{} // NewSession is called after client greeting (EHLO, HELO). func (bkd *Backend) NewSession(ctx context.Context, c *server.Conn) (context.Context, server.Session, error) { return ctx, &Session{}, nil } // A Session is returned after successful login. type Session struct { auth bool } func (s *Session) Logger(ctx context.Context) *slog.Logger { return nil } // AuthMechanisms returns a slice of available auth mechanisms; only PLAIN is // supported in this example. func (s *Session) AuthMechanisms(ctx context.Context) []string { return []string{sasl.Plain} } // Auth is the handler for supported authenticators. func (s *Session) Auth(ctx context.Context, mech string) (sasl.Server, error) { return sasl.NewPlainServer(func(identity, username, password string) error { if username != "username" || password != "password" { return errors.New("Invalid username or password") } s.auth = true return nil }), nil } func (s *Session) Mail(ctx context.Context, from string, opts *smtp.MailOptions) error { if !s.auth { return smtp.ErrAuthRequired } log.Println("Mail from:", from) return nil } func (s *Session) Verify(ctx context.Context, addr string) error { return nil } func (s *Session) Rcpt(ctx context.Context, to string, opts *smtp.RcptOptions) error { if !s.auth { return smtp.ErrAuthRequired } log.Println("Rcpt to:", to) return nil } func (s *Session) STARTTLS(ctx context.Context, tls *tls.Config) (*tls.Config, error) { return tls, nil } func (s *Session) Data(ctx context.Context, r func() io.Reader) (string, error) { if !s.auth { return "", smtp.ErrAuthRequired } if b, err := io.ReadAll(r()); err != nil { return "", err } else { log.Println("Data:", string(b)) } return "", nil } func (s *Session) Reset(ctx context.Context, _ bool) (context.Context, error) { return ctx, nil } func (s *Session) Close(ctx context.Context, err error) { } // ExampleServer runs an example SMTP server. // // It can be tested manually with e.g. netcat: // // > netcat -C localhost 1025 // EHLO localhost // AUTH PLAIN // AHVzZXJuYW1lAHBhc3N3b3Jk // MAIL FROM:<root@nsa.gov> // RCPT TO:<root@gchq.gov.uk> // DATA // Hey <3 // . func main() { be := &Backend{} addr := "localhost:1025" s := server.NewServer( server.WithBackend(be), server.WithAddr(addr), server.WithHostname("localhost"), server.WithWriteTimeout(10*time.Second), server.WithReadTimeout(10*time.Second), server.WithMaxMessageBytes(1024*1024), server.WithMaxRecipients(50), ) log.Println("Starting server at", addr) if err := s.ListenAndServe(context.Background()); err != nil { log.Fatal(err) } }
Output:
func (*Server) Close ¶
Close immediately closes all active listeners and connections.
Close returns any error returned from closing the server's underlying listener(s).
func (*Server) Listen ¶
Listen listens on the network address s.Addr to handle requests on incoming connections.
If s.Addr is blank and LMTP is disabled, ":smtp" is used.
func (*Server) ListenAndServe ¶
ListenAndServe listens on the network address s.Addr and then calls Serve to handle requests on incoming connections.
If s.Addr is blank and LMTP is disabled, ":smtp" is used.
func (*Server) Shutdown ¶
Shutdown gracefully shuts down the server without interrupting any active connections. Shutdown works by first closing all open listeners and then waiting indefinitely for connections to return to idle and then shut down. If the provided context expires before the shutdown is complete, Shutdown returns the context's error, otherwise it returns any error returned from closing the Server's underlying Listener(s).
type Session ¶
type Session interface { // Discard currently processed message. // The returning context replaces the context used in the current session. // Upgrade is true when the reset is called after a tls upgrade. Reset(ctx context.Context, upgrade bool) (context.Context, error) // Free all resources associated with session. // Error is set if an error occured during session or connection. // Close is always called after the session is done. Close(ctx context.Context, err error) // Returns logger to use when an error occurs inside a session. // If no logger is returned the default *slog.Logger is used. Logger(ctx context.Context) *slog.Logger // Set return path for currently processed message. Mail(ctx context.Context, from string, opts *smtp.MailOptions) error // Add recipient for currently processed message. Rcpt(ctx context.Context, to string, opts *smtp.RcptOptions) error // Verify checks the validity of an email address on the server. // If error is nil then smtp code 252 is send // if error is smtp status then the smtp status is send // else internal server error is returned and connection is closed Verify(ctx context.Context, addr string) error // Set currently processed message contents and send it. // If r is called then the data must be consumed completely before returning. // The queuedid must not be unique. Data(ctx context.Context, r func() io.Reader) (queueid string, err error) // AuthMechanisms returns valid auth mechanism. // Nil or an empty list means no authentication mechanism is allowed. AuthMechanisms(ctx context.Context) []string // Auth returns a matching sasl server for the given mech. Auth(ctx context.Context, mech string) (sasl.Server, error) // STARTTLS returns a valid *tls.Config. // Is called with the default tls config and the returned tls config is used in the tls upgrade. // If the tls.Config is nil or an error is returned, the tls upgrade is aborted and the connection closed. // The *tls.Config received must not be changed. STARTTLS(ctx context.Context, tls *tls.Config) (*tls.Config, error) }
Session is used by servers to respond to an SMTP client.
The methods are called when the remote client issues the matching command.