smtp

package
v0.0.0-...-0f5e0da Latest Latest
Warning

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

Go to latest
Published: Nov 1, 2023 License: MIT Imports: 12 Imported by: 10

Documentation

Index

Constants

View Source
const (
	MAX_DATA_LINE = 1000
	MAX_CMD_LINE  = 512
)

Variables

View Source
var (
	// 4yz  Transient Negative Completion reply
	// The command was not accepted, and the requested action did not
	// occur.  However, the error condition is temporary, and the action
	// may be requested again.  The sender should return to the beginning
	// of the command sequence (if any).  It is difficult to assign a
	// meaning to "transient" when two different sites (receiver- and
	// sender-SMTP agents) must agree on the interpretation.  Each reply
	// in this category might have a different time value, but the SMTP
	// client SHOULD try again.  A rule of thumb to determine whether a
	// reply fits into the 4yz or the 5yz category (see below) is that
	// replies are 4yz if they can be successful if repeated without any
	// change in command form or in properties of the sender or receiver
	// (that is, the command is repeated identically and the receiver
	// does not put up a new implementation).
	SMTPErrorTransientServiceNotAvailable           = SMTPError{Status: 421, Message: "Service not available, closing transmission channel"}
	SMTPErrorTransientMailboxNotAvailable           = SMTPError{Status: 450, Message: "Requested mail action not taken: mailbox unavailable"}
	SMTPErrorTransientLocalError                    = SMTPError{Status: 451, Message: "Requested action aborted: local error in processing"}
	SMTPErrorTransientInsufficientSystemStorage     = SMTPError{Status: 452, Message: "Requested action not taken: insufficient system storage"}
	SMTPErrorTransientUnableToAccommodateParameters = SMTPError{Status: 455, Message: "Server unable to accommodate parameters"}

	// 5yz  Permanent Negative Completion reply
	// The command was not accepted and the requested action did not
	// occur.  The SMTP client SHOULD NOT repeat the exact request (in
	// the same sequence).  Even some "permanent" error conditions can be
	// corrected, so the human user may want to direct the SMTP client to
	// reinitiate the command sequence by direct action at some point in
	// the future (e.g., after the spelling has been changed, or the user
	// has altered the account status).
	SMTPErrorPermanentSyntaxError             = SMTPError{Status: 500, Message: "Syntax error, command unrecognized"}
	SMTPErrorPermanentSyntaxErrorInParameters = SMTPError{Status: 501, Message: "Syntax error in parameters or arguments"}
	SMTPErrorPermanentCommandNotImplemented   = SMTPError{Status: 502, Message: "Command not implemented"}
	SMTPErrorPermanentBadSequence             = SMTPError{Status: 503, Message: "Bad sequence of commands"}
	SMTPErrorPermanentParameterNotImplemented = SMTPError{Status: 504, Message: "Command parameter not implemented"}
	SMTPErrorPermanentMailboxNotAvailable     = SMTPError{Status: 550, Message: "Requested action not taken: mailbox unavailable"}
	SMTPErrorPermanentUserNotLocal            = SMTPError{Status: 551, Message: "User not local"}
	SMTPErrorPermanentExceededStorage         = SMTPError{Status: 552, Message: "Requested mail action aborted: exceeded storage allocation"}
	SMTPErrorPermanentMailboxNameNotAllowed   = SMTPError{Status: 553, Message: "Requested action not taken: mailbox name not allowed"}
	SMTPErrorPermanentTransactionFailed       = SMTPError{Status: 554, Message: "Transaction failed"}
	SMTPErrorMailParametersNotImplemented     = SMTPError{Status: 555, Message: "MAIL FROM/RCPT TO parameters not recognized or not implemented"}
)
View Source
var ErrIncomplete = errors.New("incomplete data")

ErrIncomplete Incomplete data error

View Source
var ErrLtl = errors.New("line too long")

ErrLtl Line too long error

Functions

func ParseAuthPlainInitialRespone

func ParseAuthPlainInitialRespone(initialResponse string) (authorizationIdentity string, authenticationIdenity string, password string, err error)

ParseAuthPlainInitialRespone parses the base64 encoded initial response of an Auth PLAIN request

"The mechanism consists of a single message from the client to the server. The client sends the authorization identity (identity to login as), followed by a US-ASCII NulL character, followed by the authentication identity (identity whose password will be used), followed by a US-ASCII NulL character, followed by the clear-text password. The client may leave the authorization identity empty to indicate that it is the same as the authentication identity."

func ReadUntill

func ReadUntill(delim byte, max int, r io.Reader) ([]byte, error)

ReadUntill reads untill delim is found or max bytes are read. If delim was found it returns nil as error. If delim wasn't found after max bytes, it returns ErrLtl.

func SkipTillNewline

func SkipTillNewline(r io.Reader) error

SkipTillNewline removes all data untill a newline is found.

Types

type Answer

type Answer struct {
	Status  StatusCode
	Message string
}

Answer A raw SMTP answer. Used to send a status code + message.

func (Answer) String

func (c Answer) String() string

type Argument

type Argument struct {
	Key      string
	Value    string
	Operator string
}

type AuthCmd

type AuthCmd struct {
	Mechanism       string
	InitialResponse string
	R               bufio.Reader
}

func (AuthCmd) String

func (c AuthCmd) String() string

type Cmd

type Cmd interface {
	fmt.Stringer
}

Cmd All SMTP answers/commands should implement this interface.

type DataCmd

type DataCmd struct {
	Data []byte
	R    DataReader
}

func (DataCmd) String

func (c DataCmd) String() string

type DataReader

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

DataReader implements the reader that will read the data from a MAIL cmd

func NewDataReader

func NewDataReader(br *bufio.Reader) *DataReader

func (*DataReader) Read

func (r *DataReader) Read(b []byte) (n int, err error)

Implementation from textproto.DotReader.Read

type EhloCmd

type EhloCmd struct {
	Domain string
}

func (EhloCmd) String

func (c EhloCmd) String() string

type ExpnCmd

type ExpnCmd struct {
	ListName string
}

func (ExpnCmd) String

func (c ExpnCmd) String() string

type HeloCmd

type HeloCmd struct {
	Domain string
}

func (HeloCmd) String

func (c HeloCmd) String() string

type Id

type Id struct {
	Timestamp int64
	Counter   uint32
}

func (*Id) String

func (id *Id) String() string

type InvalidCmd

type InvalidCmd struct {
	// The command
	Cmd  string
	Info string
}

InvalidCmd is a known command with invalid arguments or syntax

func (InvalidCmd) String

func (c InvalidCmd) String() string

type MailAddress

type MailAddress mail.Address

func ParseAddress

func ParseAddress(rawAddress string) (MailAddress, error)

ParseAddress parses a string into a MailAddress.

func (*MailAddress) GetAddress

func (address *MailAddress) GetAddress() string

GetAddress gets the full mail address.

func (*MailAddress) GetDomain

func (address *MailAddress) GetDomain() string

GetDomain gets the domain part of a mail address. E.g the part after the @.

func (*MailAddress) GetLocal

func (address *MailAddress) GetLocal() string

GetLocal gets the local part of a mail address. E.g the part before the @.

func (*MailAddress) String

func (address *MailAddress) String() string

type MailCmd

type MailCmd struct {
	From         *MailAddress
	EightBitMIME bool
}

func (MailCmd) String

func (c MailCmd) String() string

type MailMessage

type MailMessage mail.Message

func ReadMessage

func ReadMessage(r io.Reader) (*MailMessage, error)

type MtaProtocol

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

func NewMtaProtocol

func NewMtaProtocol(c net.Conn) *MtaProtocol

NewMtaProtocol Creates a protocol that works over a socket. the net.Conn parameter will be closed when done.

func (*MtaProtocol) Close

func (p *MtaProtocol) Close()

func (*MtaProtocol) GetCmd

func (p *MtaProtocol) GetCmd() (*Cmd, error)

func (*MtaProtocol) GetIP

func (p *MtaProtocol) GetIP() net.IP

func (*MtaProtocol) GetState

func (p *MtaProtocol) GetState() *State

func (*MtaProtocol) Send

func (p *MtaProtocol) Send(c Cmd)

func (*MtaProtocol) StartTls

func (p *MtaProtocol) StartTls(c *tls.Config) error

type MultiAnswer

type MultiAnswer struct {
	Status   StatusCode
	Messages []string
}

MultiAnswer A multiline answer.

func (MultiAnswer) String

func (c MultiAnswer) String() string

type NoopCmd

type NoopCmd struct{}

func (NoopCmd) String

func (c NoopCmd) String() string

type Protocol

type Protocol interface {
	// Send a SMTP command.
	Send(Cmd)
	// Receive a command(will block while waiting for it).
	// Returns an error if something wen't wrong. E.g line was too long.
	GetCmd() (*Cmd, error)
	// Close the connection.
	Close()
	// StartTls starts the tls handshake.
	StartTls(*tls.Config) error
	// GetIP gets the ip of the client.
	GetIP() net.IP
	// Get the state that belongs to this connection.
	GetState() *State
}

Protocol Used as communication layer so we can easily switch between a real socket and a test implementation.

type QuitCmd

type QuitCmd struct {
}

func (QuitCmd) String

func (c QuitCmd) String() string

type RcptCmd

type RcptCmd struct {
	To *MailAddress
}

func (RcptCmd) String

func (c RcptCmd) String() string

type RsetCmd

type RsetCmd struct {
}

func (RsetCmd) String

func (c RsetCmd) String() string

type SMTPError

type SMTPError Answer

SMTPError describes an SMTP error with a Status and a Message list of SMTP errors: https://datatracker.ietf.org/doc/html/rfc5321#section-4.2.3

func (SMTPError) Error

func (err SMTPError) Error() string

type SamlCmd

type SamlCmd struct{}

func (SamlCmd) String

func (c SamlCmd) String() string

type SendCmd

type SendCmd struct{}

func (SendCmd) String

func (c SendCmd) String() string

type SomlCmd

type SomlCmd struct{}

func (SomlCmd) String

func (c SomlCmd) String() string

type StartTlsCmd

type StartTlsCmd struct {
}

func (StartTlsCmd) String

func (c StartTlsCmd) String() string

type State

type State struct {
	From          *MailAddress
	To            []*MailAddress
	Data          []byte
	EightBitMIME  bool
	Secure        bool
	SessionId     Id
	Ip            net.IP
	Hostname      string
	Authenticated bool
	User          User
}

State contains all the state for a single client

func (*State) AddHeader

func (s *State) AddHeader(headerKey string, headerValue string)

AddHeader prepends the given header to the state.

func (*State) AuthMatchesRcptAndMail

func (s *State) AuthMatchesRcptAndMail() (bool, string)

Check whether the auth user is allowed to send from the MAIL FROM email address and to the RCPT TO address.

func (*State) CanReceiveData

func (s *State) CanReceiveData() (bool, string)

Checks the state if the client can send a DATA command.

func (*State) CanReceiveMail

func (s *State) CanReceiveMail() (bool, string)

Checks the state if the client can send a MAIL command.

func (*State) CanReceiveRcpt

func (s *State) CanReceiveRcpt() (bool, string)

Checks the state if the client can send a RCPT command.

func (*State) GetHeader

func (s *State) GetHeader(headerKey string) (headerValue string, ok bool)

GetHeader gets a header from the state.

func (*State) Reset

func (s *State) Reset()

reset the state

type StatusCode

type StatusCode uint32
const (
	Ready             StatusCode = 220
	Closing           StatusCode = 221
	Ok                StatusCode = 250
	StartData         StatusCode = 354
	ShuttingDown      StatusCode = 421
	SyntaxError       StatusCode = 500
	SyntaxErrorParam  StatusCode = 501
	NotImplemented    StatusCode = 502
	BadSequence       StatusCode = 503
	AbortMail         StatusCode = 552
	NoValidRecipients StatusCode = 554
)

SMTP status codes

const (
	AuthenticationSucceeded                               StatusCode = 235
	EncodedString                                         StatusCode = 334
	PasswordTransitionNeeded                              StatusCode = 432
	TemporaryAuthenticationFailure                        StatusCode = 454
	AuthenticationExchangeLineTooLong                     StatusCode = 500
	MalformedAuthInput                                    StatusCode = 501
	AuthCommandNotPermittedDuringMailTransaction          StatusCode = 503
	UnrecognizedAuthenticationType                        StatusCode = 504
	AuthenticationRequired                                StatusCode = 530
	AuthenticationMechanismTooWeak                        StatusCode = 534
	AuthenticationCredentialsInvalid                      StatusCode = 535
	EncryptionRequiredForRequestedAuthenticationMechanism StatusCode = 538
)

SMTP status codes for AUTH extension (RFC 4954)

type UnknownCmd

type UnknownCmd struct {
	// The command
	Cmd  string
	Line string
}

UnknownCmd is a command that is none of the other commands. i.e. not implemented

func (UnknownCmd) String

func (c UnknownCmd) String() string

type User

type User interface {
	// Username returns the username / email address of the user.
	Username() string
}

User denotes an authenticated SMTP user.

type VrfyCmd

type VrfyCmd struct {
	Param string
}

Not implemented because of security concerns

func (VrfyCmd) String

func (c VrfyCmd) String() string

Jump to

Keyboard shortcuts

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