func (s *Parser) dotString() error {
	for {
		if err := s.atom(); err != nil {
			return err
		}
		if s.ch != '.' {
			break
		}
		s.accept.WriteByte(s.ch)
	}
	return nil
}
Dot-string     = Atom *("."  Atom)
package rfc5321
import (
	"bytes"
	"errors"
	"net"
	"strconv"
	"strings"
)
const (
	LimitPath = 256
	LimitLocalPart = 64 * 2
	LimitDomain = 255
	LimitRecipients = 100
)
var atExpected = errors.New("@ expected as part of mailbox")
type Parser struct {
	accept          bytes.Buffer
	buf             []byte
	PathParams      [][]string
	ADL             []string
	LocalPart       string
	LocalPartQuotes bool    
	Domain          string  
	IP              net.IP
	pos             int
	NullPath        bool
	ch              byte
}
func NewParser(buf []byte) *Parser {
	s := new(Parser)
	s.buf = buf
	s.pos = -1
	return s
}
func (s *Parser) Reset() {
	s.buf = s.buf[:0]
	if s.pos != -1 {
		s.pos = -1
		s.ADL = nil
		s.PathParams = nil
		s.NullPath = false
		s.LocalPart = ""
		s.Domain = ""
		s.accept.Reset()
		s.LocalPartQuotes = false
		s.IP = nil
	}
}
func (s *Parser) set(input []byte) {
	s.Reset()
	s.buf = input
}
func (s *Parser) next() byte {
	s.pos++
	if s.pos < len(s.buf) {
		s.ch = s.buf[s.pos]
		return s.ch
	}
	return 0
}
func (s *Parser) peek() byte {
	if s.pos+1 < len(s.buf) {
		return s.buf[s.pos+1]
	}
	return 0
}
func (s *Parser) reversePath() (err error) {
	if s.peek() == ' ' {
		s.next()  
	}
	if i := bytes.Index(s.buf[s.pos+1:], []byte{'<', '>'}); i == 0 {
		s.NullPath = true
		return nil
	}
	if err = s.path(); err != nil {
		return err
	}
	return nil
}
func (s *Parser) forwardPath() (err error) {
	if s.peek() == ' ' {
		s.next()  
	}
	if err = s.path(); err != nil && err != atExpected {
		return err
	}
	if i := strings.Index(strings.ToLower(s.LocalPart), postmasterLocalPart); i == 0 {
		s.LocalPart = postmasterLocalPart
		return nil  
	}
	return err  
}
func (s *Parser) MailFrom(input []byte) (err error) {
	s.set(input)
	if err := s.reversePath(); err != nil {
		return err
	}
	s.next()
	if p := s.next(); p == ' ' {
		if tup, err := s.parameters(); err != nil {
			return errors.New("param parse error")
		} else if len(tup) > 0 {
			s.PathParams = tup
		}
	}
	return nil
}
const postmasterLocalPart = "postmaster"
func (s *Parser) RcptTo(input []byte) (err error) {
	s.set(input)
	if err := s.forwardPath(); err != nil {
		return err
	}
	s.next()
	if p := s.next(); p == ' ' {
		if tup, err := s.parameters(); err != nil {
			return errors.New("param parse error")
		} else if len(tup) > 0 {
			s.PathParams = tup
		}
	}
	return nil
}
func (s *Parser) parameters() ([][]string, error) {
	params := make([][]string, 0)
	for {
		if result, err := s.param(); err != nil {
			return params, err
		} else {
			params = append(params, result)
		}
		if p := s.next(); p != ' ' {
			return params, nil
		}
	}
}
func isESMTPValue(c byte) bool {
	if ('!' <= c && c <= '<') ||
		('>' <= c && c <= '~') {
		return true
	}
	return false
}
func (s *Parser) param() (result []string, err error) {
	state := 0
	var key, value string
	defer func() {
		result = append(result, key, value)
		s.accept.Reset()
	}()
	for c := s.next(); ; c = s.next() {
		switch state {
		case 0:
			if !isLetDig(c) {
				return result, errors.New("parse error")
			}
			s.accept.WriteByte(c)
			state = 1
		case 1:
			if !isLetDig(c) {
				if c == '=' {
					key = s.accept.String()
					s.accept.Reset()
					state = 2
					continue
				} else if c == '-' {
					if p := s.peek(); !isLetDig(p) && p != '-' {
						return result, errors.New("parse error")
					}
					s.accept.WriteByte(c)
					continue
				}
				key = s.accept.String()
				return result, nil
			}
			s.accept.WriteByte(c)
		case 2:
			if !isESMTPValue(c) {
				return result, errors.New("parse error")
			}
			s.accept.WriteByte(c)
			if !isESMTPValue(s.peek()) {
				value = s.accept.String()
				return result, nil
			}
			state = 3
		case 3:
			s.accept.WriteByte(c)
			if !isESMTPValue(s.peek()) {
				value = s.accept.String()
				return result, nil
			}
		}
	}
}
func (s *Parser) path() (err error) {
	if s.next() == '<' && s.peek() == '@' {
		if err = s.adl(); err == nil {
			s.next()
			if s.ch != ':' {
				return errors.New("syntax error")
			}
		}
	}
	if err = s.mailbox(); err != nil {
		return err
	}
	if p := s.peek(); p != '>' {
		return errors.New("missing closing >")
	}
	return nil
}
func (s *Parser) adl() error {
	for {
		if err := s.atDomain(); err != nil {
			return err
		}
		s.ADL = append(s.ADL, s.accept.String())
		s.accept.Reset()
		if s.peek() != ',' {
			break
		}
		s.next()
	}
	return nil
}
func (s *Parser) atDomain() error {
	if s.next() == '@' {
		s.accept.WriteByte('@')
		return s.domain()
	}
	return errors.New("syntax error")
}
func (s *Parser) domain() error {
	for {
		if err := s.subdomain(); err != nil {
			return err
		}
		if p := s.peek(); p != '.' {
			if p != ':' && p != ',' && p != '>' && p != 0 {
				return errors.New("domain parse error")
			}
			break
		}
		s.accept.WriteByte(s.next())
	}
	return nil
}
func (s *Parser) subdomain() error {
	state := 0
	for c := s.next(); ; c = s.next() {
		switch state {
		case 0:
			p := s.peek()
			if isLetDig(c) {
				s.accept.WriteByte(c)
				if !isLetDig(p) && p != '-' {
					return nil
				}
				state = 1
				continue
			}
			return errors.New("subdomain parse err")
		case 1:
			p := s.peek()
			if isLetDig(c) || c == '-' {
				s.accept.WriteByte(c)
			}
			if !isLetDig(p) && p != '-' {
				if c == '-' {
					return errors.New("subdomain parse err")
				}
				return nil
			}
		}
	}
}
func (s *Parser) mailbox() error {
	defer func() {
		if s.accept.Len() > 0 {
			s.Domain = s.accept.String()
			s.accept.Reset()
		}
	}()
	err := s.localPart()
	if err != nil {
		return err
	}
	if s.ch != '@' {
		return atExpected
	}
	if p := s.peek(); p == '[' {
		return s.addressLiteral()
	} else {
		return s.domain()
	}
}
func (s *Parser) addressLiteral() error {
	ch := s.next()
	if ch == '[' {
		p := s.peek()
		var err error
		if p == 'I' || p == 'i' {
			for i := 0; i < 5; i++ {
				s.next()  
			}
			err = s.ipv6AddressLiteral()
		} else if p >= 48 && p <= 57 {
			err = s.ipv4AddressLiteral()
		}
		if err != nil {
			return err
		}
		if s.ch != ']' {
			return errors.New("] expected for address literal")
		}
		return nil
	}
	return nil
}
func (s *Parser) ipv4AddressLiteral() error {
	for i := 0; i < 4; i++ {
		if err := s.snum(); err != nil {
			return err
		}
		if s.ch != '.' {
			break
		}
		s.accept.WriteByte(s.ch)
	}
	ip := net.ParseIP(s.accept.String())
	if ip == nil {
		return errors.New("invalid ip")
	}
	s.IP = ip
	return nil
}
func (s *Parser) snum() error {
	state := 0
	var num bytes.Buffer
	for i := 4; i > 0; i-- {
		c := s.next()
		if state == 0 {
			if !(c >= 48 && c <= 57) {
				return errors.New("snum parse error")
			} else {
				num.WriteByte(s.ch)
				s.accept.WriteByte(s.ch)
				state = 1
				continue
			}
		}
		if state == 1 {
			if !(c >= 48 && c <= 57) {
				if v, err := strconv.Atoi(num.String()); err != nil {
					return err
				} else if v >= 0 && v <= 255 {
					return nil
				} else {
					return errors.New("invalid ipv4")
				}
			} else {
				num.WriteByte(s.ch)
				s.accept.WriteByte(s.ch)
			}
		}
	}
	return errors.New("too many digits")
}
func (s *Parser) ipv6AddressLiteral() error {
	var ip bytes.Buffer
	for c := s.next(); ; c = s.next() {
		if !(c >= 48 && c <= 57) &&
			!(c >= 65 && c <= 70) &&
			!(c >= 97 && c <= 102) &&
			c != ':' && c != '.' {
			ipstr := ip.String()
			if v := net.ParseIP(ipstr); v != nil {
				s.accept.WriteString(v.String())
				s.IP = v
				return nil
			}
			return errors.New("invalid ipv6")
		} else {
			ip.WriteByte(c)
		}
	}
}
func (s *Parser) localPart() error {
	defer func() {
		if s.accept.Len() > 0 {
			s.LocalPart = s.accept.String()
			s.accept.Reset()
		}
	}()
	p := s.peek()
	if p == '"' {
		return s.quotedString()
	} else {
		return s.dotString()
	}
}
func (s *Parser) quotedString() error {
	if s.next() == '"' {
		if err := s.QcontentSMTP(); err != nil {
			return err
		}
		if s.ch != '"' {
			return errors.New("quoted string not closed")
		} else {
			s.next()
		}
	}
	return nil
}
func (s *Parser) QcontentSMTP() error {
	state := 0
	for {
		ch := s.next()
		switch state {
		case 0:
			if ch == '\\' {
				state = 1
				continue
			} else if ch == 32 || ch == 33 ||
				(ch >= 35 && ch <= 91) ||
				(ch >= 93 && ch <= 126) {
				if s.LocalPartQuotes == false && !s.isAtext(ch) {
					s.LocalPartQuotes = true
				}
				s.accept.WriteByte(ch)
				continue
			}
			return nil
		case 1:
			if ch >= 32 && ch <= 126 {
				if s.LocalPartQuotes == false && !s.isAtext(ch) {
					s.LocalPartQuotes = true
				}
				s.accept.WriteByte(ch)
				state = 0
				continue
			} else {
				return errors.New("non-printable character found")
			}
		}
	}
}