smtpd

package module
v0.0.0-...-1ff1a6d Latest Latest
Warning

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

Go to latest
Published: Mar 8, 2023 License: MIT Imports: 27 Imported by: 0

README

Build Status

smtpd

smtpd is a pure Go implementation of an SMTP server. It allows you to do things like:

package main

import (
    "fmt"
    "net/smtp"

    "github.com/mailproto/smtpd"
)

var helloWorld = `To: sender@example.org
From: recipient@example.net
Content-Type: text/plain

This is the email body`

func main() {
    var server *smtpd.Server
    server = smtpd.NewServer(func(msg *smtpd.Message) error {
        fmt.Println("Got message from:", msg.From)
        fmt.Println(string(msg.RawBody))
        return server.Close()
    })

    go server.ListenAndServe(":2525")
    <-server.Ready

    log.Fatal(smtp.SendMail(server.Address(), nil, "sender@example.com", []string{"recipient@example.com"}, []byte(helloWorld)))
}


@todo document

Documentation

Index

Constants

View Source
const (
	DefaultReadTimeout        = time.Second * 10
	DefaultWriteTimeout       = time.Second * 10
	DefaultMessageSizeMax     = 131072
	DefaultSessionCommandsMax = 100
)

Default values

Variables

View Source
var (
	ErrAlreadyRunning = errors.New("This server is already listening for requests")
	ErrAuthFailed     = SMTPError{535, errors.New("Authentication credentials invalid")}
	ErrAuthCancelled  = SMTPError{501, errors.New("Cancelled")}
	ErrRequiresTLS    = SMTPError{538, errors.New("Encryption required for requested authentication mechanism")}
	ErrTransaction    = SMTPError{501, errors.New("Transaction unsuccessful")}
)

Well-defined errors

Functions

This section is empty.

Types

type Auth

type Auth struct {
	Mechanisms map[string]AuthExtension
}

func NewAuth

func NewAuth() *Auth

func (*Auth) EHLO

func (a *Auth) EHLO() string

EHLO returns a stringified list of the installed Auth mechanisms

func (*Auth) Extend

func (a *Auth) Extend(mechanism string, extension AuthExtension) error

Extend the auth handler by adding a new mechanism

func (*Auth) Handle

func (a *Auth) Handle(c *Conn, args string) error

Handle authentication by handing off to one of the configured auth mechanisms

type AuthCramMd5

type AuthCramMd5 struct {
	FindUser func(string) (AuthUser, error)
}

func (*AuthCramMd5) CheckResponse

func (a *AuthCramMd5) CheckResponse(response string, challenge []byte) (AuthUser, bool)

Note: This is currently very weak & requires storing of the user's password in plaintext one good alternative is to do the HMAC manually and expose handlers for pre-processing the password MD5s

func (*AuthCramMd5) Handle

func (a *AuthCramMd5) Handle(conn *Conn, params string) (AuthUser, error)

Handles the negotiation of an AUTH CRAM-MD5 request https://en.wikipedia.org/wiki/CRAM-MD5 http://www.samlogic.net/articles/smtp-commands-reference-auth.htm

type AuthPlain

type AuthPlain struct {
	Auth SimpleAuthFunc
}

func (*AuthPlain) Handle

func (a *AuthPlain) Handle(conn *Conn, params string) (AuthUser, error)

Handles the negotiation of an AUTH PLAIN request

type AuthUser

type AuthUser interface {
	IsUser(value string) bool
	Password() string
}

AuthUser should check if a given string identifies that user

type Conn

type Conn struct {
	// Conn is primarily a wrapper around a net.Conn object
	net.Conn

	// Track some mutable for this connection
	IsTLS    bool
	Errors   []error
	User     AuthUser
	FromAddr *mail.Address
	ToAddr   []*mail.Address

	// Configuration options
	MaxSize      int64
	ReadTimeout  time.Duration
	WriteTimeout time.Duration
	// contains filtered or unexported fields
}

Conn is a wrapper for net.Conn that provides convenience handlers for SMTP requests

func (*Conn) EndTX

func (c *Conn) EndTX() error

EndTX closes off a MAIL transaction and returns a message object

func (*Conn) ReadData

func (c *Conn) ReadData() (string, error)

ReadData brokers the special case of SMTP data messages

func (*Conn) ReadLine

func (c *Conn) ReadLine() (string, error)

ReadLine reads a single line from the client

func (*Conn) ReadSMTP

func (c *Conn) ReadSMTP() (string, string, error)

ReadSMTP pulls a single SMTP command line (ending in a carriage return + newline)

func (*Conn) Reset

func (c *Conn) Reset()

func (*Conn) StartTX

func (c *Conn) StartTX(from *mail.Address) error

StartTX starts a new MAIL transaction

func (*Conn) WriteEHLO

func (c *Conn) WriteEHLO(message string) error

WriteEHLO writes an EHLO line, see https://tools.ietf.org/html/rfc2821#section-4.1.1.1

func (*Conn) WriteOK

func (c *Conn) WriteOK() error

WriteOK is a convenience function for sending the default OK response

func (*Conn) WriteSMTP

func (c *Conn) WriteSMTP(code int, message string) error

WriteSMTP writes a general SMTP line

type Extension

type Extension interface {
	Handle(*Conn, string) error
	EHLO() string
}

type Message

type Message struct {
	To      []*mail.Address
	From    *mail.Address
	Header  mail.Header
	Subject string
	RawBody []byte
	Source  []byte

	// meta info
	Logger *log.Logger
	// contains filtered or unexported fields
}

Message is a nicely packaged representation of the recieved message

func NewMessage

func NewMessage(data []byte, rcpt []*mail.Address, logger *log.Logger) (*Message, error)

NewMessage creates a Message from a data blob and a recipients list

func (*Message) Attachments

func (m *Message) Attachments() ([]*Part, error)

Attachments returns the list of attachments on this message XXX: this assumes that the only mimetype supporting attachments is multipart/mixed need to review https://en.wikipedia.org/wiki/MIME#Multipart_messages to ensure that is the case

func (*Message) BCC

func (m *Message) BCC() []*mail.Address

BCC returns a list of addresses this message should be

func (*Message) FindBody

func (m *Message) FindBody(contentType string) ([]byte, error)

FindBody finds the first part of the message with the specified Content-Type

func (*Message) HTML

func (m *Message) HTML() ([]byte, error)

HTML returns the text/html content of the message, if any

func (*Message) ID

func (m *Message) ID() string

ID returns an identifier for this message, or generates one if none available using the masked string algorithm from https://stackoverflow.com/questions/22892120/how-to-generate-a-random-string-of-a-fixed-length-in-golang

func (*Message) Parts

func (m *Message) Parts() ([]*Part, error)

Parts breaks a message body into its mime parts

func (*Message) Plain

func (m *Message) Plain() ([]byte, error)

Plain returns the text/plain content of the message, if any

type MessageHandler

type MessageHandler func(m *Message) error

MessageHandler functions handle application of business logic to the inbound message

type Part

type Part struct {
	Header textproto.MIMEHeader

	Body     []byte
	Children []*Part
	// contains filtered or unexported fields
}

Part represents a single part of the message

type SMTPError

type SMTPError struct {
	Code int
	Err  error
}

SMTPError is an error + SMTP response code

func NewError

func NewError(code int, message string) SMTPError

NewError creates an SMTPError with the supplied code

func (SMTPError) Error

func (a SMTPError) Error() string

Error pulls the base error value

type Server

type Server struct {
	Name string

	TLSConfig  *tls.Config
	ServerName string

	// MaxSize of incoming message objects, zero for no cap otherwise
	// larger messages are thrown away
	MaxSize int64

	// MaxConn limits the number of concurrent connections being handled
	MaxConn int

	// MaxCommands is the maximum number of commands a server will accept
	// from a single client before terminating the session
	MaxCommands int

	// RateLimiter gets called before proceeding through to message handling
	// TODO: Implement
	RateLimiter func(*Conn) bool

	// Handler is the handoff function for messages
	Handler MessageHandler

	// Auth is an authentication-handling extension
	Auth Extension

	// Extensions is a map of server-specific extensions & overrides, by verb
	Extensions map[string]Extension

	// Disabled features
	Disabled map[string]bool

	// help message to display in response to a HELP request
	Help string

	// Logger to print out status info
	// TODO: implement better logging with configurable verbosity
	Logger *log.Logger

	Verbose bool

	// Timeout handlers
	ReadTimeout  time.Duration
	WriteTimeout time.Duration

	// Ready is a channel that will receive a single `true` when the server has started
	Ready chan bool
	// contains filtered or unexported fields
}

Server is an RFC2821/5321 compatible SMTP server

func NewServer

func NewServer(handler func(*Message) error) *Server

NewServer creates a server with the default settings

func NewServerWithLogger

func NewServerWithLogger(handler func(*Message) error, logger *log.Logger) *Server

NewServerWithLogger creates a server with a customer logger

func (*Server) Address

func (s *Server) Address() string

Address retrieves the address of the server

func (*Server) Close

func (s *Server) Close() error

Close the server connection

func (*Server) Disable

func (s *Server) Disable(verbs ...string)

Disable server capabilities

func (*Server) Enable

func (s *Server) Enable(verbs ...string)

Enable server capabilities that have previously been disabled

func (*Server) Extend

func (s *Server) Extend(verb string, extension Extension) error

Extend the server to handle the supplied verb

func (*Server) GetAddressArg

func (s *Server) GetAddressArg(argName string, args string) (*mail.Address, error)

GetAddressArg extracts the address value from a supplied SMTP argument for handling MAIL FROM:address@example.com and RCPT TO:address@example.com XXX: don't like this, feels like a hack

func (*Server) Greeting

func (s *Server) Greeting(conn *Conn) string

Greeting is a humanized response to EHLO to precede the list of available commands

func (*Server) HandleSMTP

func (s *Server) HandleSMTP(conn *Conn) error

HandleSMTP handles a single SMTP request

func (*Server) ListenAndServe

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

ListenAndServe starts listening for SMTP commands at the supplied TCP address

func (*Server) SetHelp

func (s *Server) SetHelp(message string) error

SetHelp sets a help message

func (*Server) UseAuth

func (s *Server) UseAuth(auth Extension)

UseAuth assigns the server authentication extension

func (*Server) UseTLS

func (s *Server) UseTLS(cert, key string) error

UseTLS tries to enable TLS on the server (can also just explicitly set the TLSConfig)

type SimpleAuthFunc

type SimpleAuthFunc func(string, string) (AuthUser, bool)

type SimpleExtension

type SimpleExtension struct {
	Handler func(*Conn, string) error
	Ehlo    string
}

func (*SimpleExtension) EHLO

func (s *SimpleExtension) EHLO() string

func (*SimpleExtension) Handle

func (s *SimpleExtension) Handle(c *Conn, args string) error

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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