server

package
v0.0.16 Latest Latest
Warning

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

Go to latest
Published: May 19, 2025 License: MIT Imports: 19 Imported by: 1

Documentation

Index

Examples

Constants

View Source
const (
	StateInit = iota
	StateUpgrade
	StateEnforceAuthentication
	StateEnforceSecureConnection
	StateGreeted
	StateMail
)

Variables

View Source
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

type BackendFunc func(ctx context.Context, c *Conn) (context.Context, Session, error)

BackendFunc is an adapter to allow the use of an ordinary function as a Backend.

func (BackendFunc) NewSession

func (f BackendFunc) NewSession(ctx context.Context, c *Conn) (context.Context, Session, error)

NewSession calls f(c). The returning context is used in the session.

type Conn

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

func (*Conn) Close

func (c *Conn) Close(err error)

func (*Conn) Conn

func (c *Conn) Conn() net.Conn

func (*Conn) Hostname

func (c *Conn) Hostname() string

func (*Conn) IsTLS

func (c *Conn) IsTLS() bool

IsTLS returns if the connection is encrypted by tls.

func (*Conn) Mechanisms added in v0.0.7

func (c *Conn) Mechanisms() []string

func (*Conn) Reject

func (c *Conn) Reject(ctx context.Context)

func (*Conn) Server

func (c *Conn) Server() *Server

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 WithAddr

func WithAddr(addr string) Option

WithAddr sets addr.

func WithBackend

func WithBackend(backend Backend) Option

WithBackend sets the backend.

func WithEnableBINARYMIME

func WithEnableBINARYMIME(enableBINARYMIME bool) Option

WithEnableBINARYMIME sets EnableBINARYMIME.

func WithEnableCHUNKING

func WithEnableCHUNKING(enableCHUNKING bool) Option

WithEnableCHUNKING sets EnableCHUNKING.

func WithEnableDSN

func WithEnableDSN(enableDSN bool) Option

WithEnableDSN sets EnableDSN.

func WithEnableREQUIRETLS

func WithEnableREQUIRETLS(enableREQUIRETLS bool) Option

WithEnableREQUIRETLS sets EnableREQUIRETLS.

func WithEnableSMTPUTF8

func WithEnableSMTPUTF8(enableSMTPUTF8 bool) Option

WithEnableSMTPUTF8 sets EnableSMTPUTF8.

func WithEnableXOORG

func WithEnableXOORG(enableXOORG bool) Option

WithEnableXOORG enables xoorg.

func WithEnforceAuthentication

func WithEnforceAuthentication(enforceAuthentication bool) Option

WithEnforceAuthentication enforces authentication before mail usage.

func WithEnforceSecureConnection

func WithEnforceSecureConnection(enforceSecureConnection bool) Option

WithEnforceSecureConnection enforces implicit TLS or STARTTLS.

func WithHostname

func WithHostname(hostname string) Option

WithHostname sets the domain.

func WithImplicitTLS

func WithImplicitTLS(implicitTLS bool) Option

WithImplicitTLS sets implicitTLS.

func WithLogger

func WithLogger(logger *slog.Logger) Option

WithLogger sets the backend.

func WithMaxLineLength

func WithMaxLineLength(maxLineLength int) Option

WithMaxLineLength sets the max length per line.

func WithMaxMessageBytes

func WithMaxMessageBytes(maxMessageBytes int64) Option

WithMaxMessageBytes sets the max message size.

func WithMaxRecipients

func WithMaxRecipients(maxRecipients int) Option

WithMaxRecipients sets the max recipients per mail.

func WithNetwork

func WithNetwork(network string) Option

WithNetwork sets the network.

func WithReadTimeout

func WithReadTimeout(readTimeout time.Duration) Option

WithReadTimeout sets the read timeout.

func WithReaderSize

func WithReaderSize(readerSize int) Option

WithReaderSize sets ReaderSize.

func WithTLSConfig

func WithTLSConfig(tlsConfig *tls.Config) Option

WithTLSConfig sets certificate.

func WithWriteTimeout

func WithWriteTimeout(writeTimeout time.Duration) Option

WithWriteTimeout sets the write timeout.

func WithWriterSize

func WithWriterSize(writerSize int) Option

WithWriterSize sets WriterSize.

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 NewServer

func NewServer(opts ...Option) *Server

New creates a new SMTP server.

func (*Server) Address added in v0.0.14

func (s *Server) Address() string

Address returns the servers address.

func (*Server) Backend added in v0.0.14

func (s *Server) Backend() Backend

Backend returns the servers Backend.

func (*Server) Close

func (s *Server) Close(ctx context.Context) error

Close immediately closes all active listeners and connections.

Close returns any error returned from closing the server's underlying listener(s).

func (*Server) Listen

func (s *Server) Listen(ctx context.Context) (net.Listener, error)

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

func (s *Server) ListenAndServe(ctx context.Context) error

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) Serve

func (s *Server) Serve(ctx context.Context, l net.Listener) error

Serve accepts incoming connections on the Listener l.

func (*Server) Shutdown

func (s *Server) Shutdown(ctx context.Context) error

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.

Jump to

Keyboard shortcuts

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