gosmtp

package module
v0.0.0-...-b485801 Latest Latest
Warning

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

Go to latest
Published: Jan 9, 2021 License: MIT Imports: 16 Imported by: 1

README

GOSMTP

GOSMTP is golang implementation of full-featured, RFC standard compliant and lightweight SMTP server.

Mail Transport Agent

Accepts and handles incoming mail. Supported authentication methods:

  • PLAIN
  • LOGIN

Setup

Download
  1. Download

  2. Clone

Config

Minimal configuration you will need might look like this:

me: example.com

With this minimal configuration you will be able to run your email server at given domain. This server will use defaults for all you haven't specified.

Run

To start the server just simply run

./mamail

About

TLS

GOSMTP aims to be secure and modern. TLS should be always allowed as specified in

As a result, clients and servers SHOULD implement both STARTTLS on port 587 and Implicit TLS on port 465 for this transition period. Note that there is no significant difference between the security properties of STARTTLS on port 587 and Implicit TLS on port 465 if the implementations are correct and if both the client and the server are configured to require successful negotiation of TLS prior to Message Submission.

Fot testing purpouses one can generate certificate via https://github.com/deckarep/EasyCert

DNS
MX Records

It is recommended that MSPs advertise MX records for the handling of inbound mail (instead of relying entirely on A or AAAA records) and that those MX records be signed using DNSSEC [RFC4033]. This is mentioned here only for completeness, as the handling of inbound mail is out of scope for this document.

SRV Records

MSPs SHOULD advertise SRV records to aid MUAs in determining the proper configuration of servers, per the instructions in [RFC6186].

MSPs SHOULD advertise servers that support Implicit TLS in preference to servers that support cleartext and/or STARTTLS operation.

DNSSEC

All DNS records advertised by an MSP as a means of aiding clients in communicating with the MSP's servers SHOULD be signed using DNSSEC if and when the parent DNS zone supports doing so.

TLSA Records

MSPs SHOULD advertise TLSA records to provide an additional trust anchor for public keys used in TLS server certificates. However, TLSA records MUST NOT be advertised unless they are signed using DNSSEC.

SPF

Publishing Authorization

An SPF-compliant domain MUST publish a valid SPF record as described in Section 3. This record authorizes the use of the domain name in the "HELO" and "MAIL FROM" identities by the MTAs it specifies.

If domain owners choose to publish SPF records, it is RECOMMENDED that they end in "-all", or redirect to other records that do, so that a definitive determination of authorization can be made.

Domain holders may publish SPF records that explicitly authorize no hosts if mail should never originate using that domain.

When changing SPF records, care must be taken to ensure that there is a transition period so that the old policy remains valid until all legitimate E-Mail has been checked.

Contributing

Goals
  • full-featured, production ready MTA agent
  • easily extensible

Documentation

Index

Constants

View Source
const (
	// ClassSuccess specifies that the DSN is reporting a positive delivery
	// action.  Detail sub-codes may provide notification of
	// transformations required for delivery.
	ClassSuccess = 2
	// ClassTransientFailure - a persistent transient failure is one in which the message as
	// sent is valid, but persistence of some temporary condition has
	// caused abandonment or delay of attempts to send the message.
	// If this code accompanies a delivery failure report, sending in
	// the future may be successful.
	ClassTransientFailure = 4
	// ClassPermanentFailure - a permanent failure is one which is not likely to be resolved
	// by resending the message in the current form.  Some change to
	// the message or the destination must be made for successful
	// delivery.
	ClassPermanentFailure = 5
)
View Source
const (
	// SubjectUndefined - There is no additional subject information available
	SubjectUndefined = 0
	// SubjectAddressing - The address status reports on the originator or destination address.
	// It may include address syntax or validity.
	// These errors can generally be corrected by the sender and retried.
	SubjectAddressing = 1
	// SubjectMailbox - Mailbox status indicates that something having to do with the mailbox has caused this DSN.
	// Mailbox issues are assumed to be under the general control of the recipient.
	SubjectMailbox = 2
	// SubjectMail - Mail system status indicates that something having to do with the destination system has caused this DSN.
	// System issues are assumed to be under the general control of the destination system administrator.
	SubjectMail = 3
	// SubjectNetwork - The networking or routing codes report status about the delivery system itself.
	// These system components include any necessary infrastructure such as directory and routing services.
	// Network issues are assumed to be under the control of the destination or intermediate system administrator.
	SubjectNetwork = 4
	// SubjectDelivery - The mail delivery protocol status codes report failures involving the message delivery protocol.
	// These failures include the full range of problems resulting from implementation errors or an unreliable connection.
	SubjectDelivery = 5
	// SubjectContent - The message content or media status codes report failures involving the content of the message.
	// These codes report failures due to translation, transcoding, or otherwise unsupported message media.
	// Message content or media issues are under the control of both the sender and the receiver,
	// both of which must support a common set of supported content-types.
	SubjectContent = 6
	// SubjectPolicy - The security or policy status codes report failures involving policies such as per-recipient or
	// per-host filtering and cryptographic operations.
	// Security and policy status issues are assumed to be under the control of either or both the sender and recipient.
	// Both the sender and recipient must permit the exchange of messages and arrange the exchange of necessary keys and
	// certificates for cryptographic operations.
	SubjectPolicy = 7
)
View Source
const (
	OtherStatus                               = ".0.0"
	OtherAddressStatus                        = ".1.0"
	BadDestinationMailboxAddress              = ".1.1"
	BadDestinationSystemAddress               = ".1.2"
	BadDestinationMailboxAddressSyntax        = ".1.3"
	DestinationMailboxAddressAmbiguous        = ".1.4"
	DestinationMailboxAddressValid            = ".1.5"
	MailboxHasMoved                           = ".1.6"
	BadSendersMailboxAddressSyntax            = ".1.7"
	BadSendersSystemAddress                   = ".1.8"
	OtherOrUndefinedMailboxStatus             = ".2.0"
	MailboxDisabled                           = ".2.1"
	MailboxFull                               = ".2.2"
	MessageLengthExceedsAdministrativeLimit   = ".2.3"
	MailingListExpansionProblem               = ".2.4"
	OtherOrUndefinedMailSystemStatus          = ".3.0"
	MailSystemFull                            = ".3.1"
	SystemNotAcceptingNetworkMessages         = ".3.2"
	SystemNotCapableOfSelectedFeatures        = ".3.3"
	MessageTooBigForSystem                    = ".3.4"
	OtherOrUndefinedNetworkOrRoutingStatus    = ".4.0"
	NoAnswerFromHost                          = ".4.1"
	BadConnection                             = ".4.2"
	RoutingServerFailure                      = ".4.3"
	UnableToRoute                             = ".4.4"
	NetworkCongestion                         = ".4.5"
	RoutingLoopDetected                       = ".4.6"
	DeliveryTimeExpired                       = ".4.7"
	OtherOrUndefinedProtocolStatus            = ".5.0"
	InvalidCommand                            = ".5.1"
	SyntaxError                               = ".5.2"
	TooManyRecipients                         = ".5.3"
	InvalidCommandArguments                   = ".5.4"
	WrongProtocolVersion                      = ".5.5"
	OtherOrUndefinedMediaError                = ".6.0"
	MediaNotSupported                         = ".6.1"
	ConversionRequiredAndProhibited           = ".6.2"
	ConversionRequiredButNotSupported         = ".6.3"
	ConversionWithLossPerformed               = ".6.4"
	ConversionFailed                          = ".6.5"
	SecurityStatus                            = ".7.0"
	DeliveryNotAuthorized                     = ".7.1"
	MailingListExpansionProhibited            = ".7.2"
	SecurityConversionRequiredButNotSupported = ".7.3"
	EncryptionNeeded                          = ".7.10"
)

DefaultMap contains defined default codes (RfC 3463)

Variables

View Source
var DefaultLimits = Limits{
	CmdInput:     2 * time.Minute,
	MsgInput:     10 * time.Minute,
	ReplyOut:     2 * time.Minute,
	TLSSetup:     4 * time.Minute,
	MsgSize:      5 * 1024 * 1024,
	BadCmds:      5,
	MaxRcptCount: 200,
}

DefaultLimits that are applied if you do not specify custom limits Two minutes for command input and command replies, ten minutes for receiving messages, and 5 Mbytes of message size.

Note that these limits are not necessarily RFC compliant, although they should be enough for real email clients, TODO change this to RFC compliant

View Source
var ErrorRecipientNotFound = errors.New("Couldn't find recipient with given email address")

ErrorRecipientNotFound is returned when the email is inbound but the user is not found

View Source
var ErrorRecipientsMailboxFull = errors.New("Recipients mailbox is full")

ErrorRecipientsMailboxFull is returned when the user's mailbox is full

View Source
var SupportedAuthMechanisms = []string{"LOGIN", "PLAIN"}

SupportedAuthMechanisms is array of string describing currently supported/implemented authentication mechanisms

Functions

func IsFQN

func IsFQN(addr *mail.Address) string

IsFQN checks if email host is full qualified name (MX or A record)

Types

type DummyMailStore

type DummyMailStore struct{}

DummyMailStore for testing purpouses, doesn't handle the mail

func (*DummyMailStore) Handle

func (dms *DummyMailStore) Handle(envelope *Envelope, user string) (id string, err error)

Handle discards the email

type EnhancedStatusCode

type EnhancedStatusCode struct {
	Class             class
	SubjectDetailCode subjectDetail
}

EnhancedStatus are the ones that look like 2.1.0

func (EnhancedStatusCode) String

func (e EnhancedStatusCode) String() string

String returns a string representation of EnhancedStatus

type Envelope

type Envelope struct {
	MailFrom *mail.Address   // Envelope sender
	MailTo   []*mail.Address // Envelope recipients
	Mail     *mail.Message   // Final message
	Priority int
	// contains filtered or unexported fields
}

Envelope represents a message envelope

func NewEnvelope

func NewEnvelope() *Envelope

func (*Envelope) AddRecipient

func (e *Envelope) AddRecipient(rcpt *mail.Address) error

AddRecipient adds recipient to envelope recipients returns error if maximum number of recipients is reached

func (*Envelope) BeginData

func (e *Envelope) BeginData() error

func (*Envelope) Bytes

func (e *Envelope) Bytes() []byte

func (*Envelope) Close

func (e *Envelope) Close() (err error)

Close the envelope before handing it futher

func (*Envelope) IsSet

func (e *Envelope) IsSet() bool

IsSet returns if the envelope is set

func (*Envelope) Reader

func (e *Envelope) Reader() *bytes.Reader

Reader returns reader for envelope data

func (*Envelope) Reset

func (e *Envelope) Reset() error

Reset resets envelope to initial state

func (*Envelope) Write

func (e *Envelope) Write(line []byte) (int, error)

Write writes bytes into the envelope buffer

func (*Envelope) WriteLine

func (e *Envelope) WriteLine(line []byte) (int, error)

WriteLine writes data into the envelope followed by new line

func (*Envelope) WriteString

func (e *Envelope) WriteString(line string) (int, error)

WriteString writes string into the envelope buffer

type Limits

type Limits struct {
	CmdInput     time.Duration // client commands
	MsgInput     time.Duration // total time for the email
	ReplyOut     time.Duration // server reply time
	TLSSetup     time.Duration // time limit for STARTTLS setup
	MsgSize      int64         // max email size
	BadCmds      int           // bad commands limit
	MaxRcptCount int           // maximum number of recipients of message
}

Limits hold all the session limitations - max attempts, sizes and timeouts

type MailHandler

type MailHandler interface {
	Handle(envelope *Envelope, user string) (id string, err error)
}

MailHandler is object on which func Handle(envelope, user) is called after the whole mail is received MailHandler can be for example object which passes the email to MDA (mail delivery agent) for remote delivery or to Dovercot to save the mail to the users inbox

type Peer

type Peer struct {
	HeloName        string
	HeloType        string
	Protocol        Protocol
	ServerName      string
	Username        string
	Authenticated   bool
	Addr            net.Addr
	TLS             *tls.ConnectionState
	AdditionalField map[string]interface{}
}

Peer represents the client connecting to the server

type Protocol

type Protocol string

Protocol represents the protocol used in the SMTP session

const (
	SMTP  Protocol = "SMTP"  // SMTP - plain old SMTP
	ESMTP          = "ESMTP" // ESMTP - Extended SMTP
)

type Response

type Response struct {
	EnhancedCode subjectDetail
	BasicCode    int
	Class        class
	// Comment is optional
	Comment string
}

Response type for Stringer interface

func (*Response) String

func (r *Response) String() string

String returns a custom Response as a string

type Responses

type Responses struct {
	// The 500's
	FailLineTooLong                        string
	FailNestedMailCmd                      string
	FailNoSenderDataCmd                    string
	FailNoRecipientsDataCmd                string
	FailUnrecognizedCmd                    string
	FailMaxUnrecognizedCmd                 string
	FailReadLimitExceededDataCmd           string
	FailMessageSizeExceeded                string
	FailReadErrorDataCmd                   string
	FailPathTooLong                        string
	FailInvalidAddress                     string
	FailLocalPartTooLong                   string
	FailInvalidExtension                   string
	FailAuthentication                     string
	FailUnqalifiedHostName                 string
	FailDomainTooLong                      string
	FailBackendNotRunning                  string
	FailBackendTransaction                 string
	FailTooBig                             string
	FailBackendTimeout                     string
	FailRcptCmd                            string
	FailCmdNotSupported                    string
	FailRelayAccessDenied                  string
	FailMailboxDoesntExist                 string
	FailMailboxFull                        string
	FailBadSenderMailboxAddressSyntax      string
	FailBadDestinationMailboxAddressSyntax string
	FailAccessDenied                       string
	FailBadSequence                        string
	FailInvalidRecipient                   string
	FailEncryptionNeeded                   string
	FailMissingArgument                    string
	FailUndefinedSecurityStatus            string

	// The 400's
	ErrorTooManyRecipients      string
	ErrorRelayDenied            string
	ErrorShutdown               string
	ErrorRelayAccess            string
	ErrorAuth                   string
	ErrorUnableToResolveHost    string
	ErrorCmdParamNotImplemented string

	// The 200's
	SuccessAuthentication string
	SuccessMailCmd        string
	SuccessRcptCmd        string
	SuccessResetCmd       string
	SuccessVerifyCmd      string
	SuccessNoopCmd        string
	SuccessQuitCmd        string
	SuccessDataCmd        string
	SuccessHelpCmd        string
	SuccessStartTLSCmd    string
	SuccessMessageQueued  string
}

Responses has some already pre-constructed responses

var (
	// Codes is to be read-only, except in the init() function
	Codes Responses
)

type Server

type Server struct {
	sync.Mutex
	Addr      string      // TCP address to listen on, ":25" if empty
	Hostname  string      // hostname, e.g. the domain which the server runs on
	TLSConfig *tls.Config // TLS configuration
	TLSOnly   bool

	// Limits
	Limits Limits

	// New e-mails are handed off to this function.
	// Can be left empty for a NOOP server.
	// Returned ID should be ID of the queued email if the email is put into outgoing queue
	// If an error is returned, it will be reported in the SMTP session.
	Handler func(peer *Peer, env *Envelope) (string, error)

	// Enable PLAIN/LOGIN authentication
	Authenticator func(peer *Peer, password []byte) (bool, error)

	// Enable various checks during the SMTP session.
	// Can be left empty for no restrictions.
	// If an error is returned, it will be reported in the SMTP session.
	// Use the Error struct for access to error codes.
	ConnectionChecker func(peer *Peer) error                     // Called upon new connection.
	HeloChecker       func(peer *Peer, name string) error        // Called after HELO/EHLO.
	SenderChecker     func(peer *Peer, addr *mail.Address) error // Called after MAIL FROM.
	RecipientChecker  func(peer *Peer, addr *mail.Address) error // Called after each RCPT TO.
	// contains filtered or unexported fields
}

Server - full feature, RFC compliant, SMTP server implementation

func NewServer

func NewServer(port string, logger *log.Logger, limits ...Limits) (*Server, error)

NewServer creates new server

func (*Server) Auth

func (srv *Server) Auth(f func(*Peer, []byte) (bool, error), mechanisms ...string) error

Auth sets the authentication function and authentication mechanisms which will be used

func (*Server) ListenAndServe

func (srv *Server) ListenAndServe() error

ListenAndServe listens on the TCP network address and then calls Serve to handle requests on incoming connections. Connections are handled securely if it is available

func (*Server) Serve

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

Serve incoming connections Creates new session for each connection and starts go routine to handle it

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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