Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions README
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
Smtpd is a Go package for handling the server side of the SMTP protocol.
It does not handle high level details like what addresses should be
Smtpd is a Go package for handling the server side of the LMTP & SMTP
protocol. It does not handle high level details like what addresses should be
accepted or what should happen with email once it has been fully received;
those decisions are instead delegated to whatever is driving smtpd.
Smtpd's purpose is simply to handle the grunt work of a reasonably
RFC compliant SMTP server, taking care of things like proper command
sequencing, TLS, and basic correctness of some things.
those decisions are instead delegated to whatever is driving smtpd. Smtpd's
purpose is simply to handle the grunt work of a reasonably RFC compliant SMTP
server, taking care of things like proper command sequencing, TLS, and basic
correctness of some things.

(The standard library net/smtp package handles only the client side
of SMTP; it makes no attempt to provide the facilities you'd need to
Expand Down
57 changes: 56 additions & 1 deletion smtpd.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ const (
HELP
AUTH
STARTTLS
LHLO
)

// ParsedLine represents a parsed SMTP command line. Err is set if
Expand Down Expand Up @@ -97,6 +98,7 @@ var smtpCommand = []struct {
}{
{HELO, "HELO", canArg},
{EHLO, "EHLO", canArg},
{LHLO, "LHLO", canArg},
{MAILFROM, "MAIL FROM", colonAddress},
{RCPTTO, "RCPT TO", colonAddress},
{DATA, "DATA", noArg},
Expand Down Expand Up @@ -311,6 +313,7 @@ var states = map[Command]struct {
}{
HELO: {sInitial | sHelo, sHelo},
EHLO: {sInitial | sHelo, sHelo},
LHLO: {sInitial | sHelo, sHelo},
AUTH: {sHelo, sHelo},
MAILFROM: {sHelo, sMail},
RCPTTO: {sMail | sRcpt, sRcpt},
Expand Down Expand Up @@ -579,7 +582,7 @@ func (c *Conn) Accept() {
switch c.curcmd {
case HELO:
c.reply("250 %s Hello %v", c.Config.LocalName, c.conn.RemoteAddr())
case EHLO:
case EHLO, LHLO:
c.reply("250-%s Hello %v", c.Config.LocalName, c.conn.RemoteAddr())
// We advertise 8BITMIME per
// http://cr.yp.to/smtp/8bitmime.html
Expand Down Expand Up @@ -746,6 +749,58 @@ func (c *Conn) Tempfail() {
c.replied = true
}

// A variant of LmtpRejectMsg suitable for using in the responses to the DATA
// command in LMTP. It won't advance the state machine, so multiple commands
// can be issued under control of the caller.
func (c *Conn) LmtpRejectMsg(format string, elems ...interface{}) {
c.RejectMsg(format, elems...)
if c.state == sPostData {
c.state = sData
c.nstate = sPostData
}
c.replied = false
}

// A variant of LmtpTempfailMsg suitable for using in the responses to the DATA
// command in LMTP. It won't advance the state machine, so multiple commands
// can be issued under control of the caller.
func (c *Conn) LmtpTempfailMsg(format string, elems ...interface{}) {
c.TempfailMsg(format, elems...)
if c.state == sPostData {
c.state = sData
c.nstate = sPostData
}
c.replied = false
}

// A variant of LmtpAcceptMsg suitable for using in the responses to the DATA
// command in LMTP. It won't advance the state machine, so multiple commands
// can be issued under control of the caller.
func (c *Conn) LmtpAcceptMsg(format string, elems ...interface{}) {
if c.curcmd == DATA {
c.replyMulti(250, format, elems...)
} else {
c.AcceptMsg(format, elems)
}

if c.state == sPostData {
c.state = sData
c.nstate = sPostData
}

c.replied = false
}

// Advance the protocol machine and prevent automatic responses, as with LMTP
// the caller is driving the conversation and should have already replied.
func (c *Conn) LmtpDataAccept() {
if c.replied {
return
}
c.state = c.nstate
c.replied = true
}

// mimeParam() returns true if the parameter argument of a MAIL FROM
// is what we expect for a client exploiting our advertisement of
// 8BITMIME.
Expand Down