func (cl *Client) Quit() (res *Response, err error) {
	_, err = cl.conn.Write([]byte("QUIT\r\n"))
	if err == nil {
		res, err = cl.recv()
	}
	errClose := cl.conn.Close()
	if errClose != nil {
		if err == nil {
			err = errClose
		}
	}
	return res, err
}
Quit signal the server that the client will close the connection.
package smtp
import (
	"bytes"
	"crypto/tls"
	"encoding/base64"
	"errors"
	"fmt"
	"io"
	"net"
	"net/url"
	"os"
	"strings"
	"github.com/shuLhan/share/lib/debug"
	libnet "github.com/shuLhan/share/lib/net"
)
type Client struct {
	ServerInfo *ServerInfo
	data []byte
	buf  bytes.Buffer
	serverName string
	raddr      *net.TCPAddr
	conn       net.Conn
	insecure   bool
	isTLS      bool
	isStartTLS bool
}
func NewClient(localName, remoteURL string, insecure bool) (cl *Client, err error) {
	var (
		logp   = "NewClient"
		rurl   *url.URL
		port   uint16
		scheme string
	)
	rurl, err = url.Parse(remoteURL)
	if err != nil {
		return nil, fmt.Errorf("smtp: %s: %w", logp, err)
	}
	cl = &Client{
		raddr:    &net.TCPAddr{},
		insecure: insecure,
	}
	scheme = strings.ToLower(rurl.Scheme)
	switch scheme {
	case "smtp":
		port = 25
	case "smtps":
		port = 465
		cl.isTLS = true
	case "smtp+starttls":
		port = 587
		cl.isStartTLS = true
	default:
		return nil, fmt.Errorf("smtp: %s: invalid scheme %q", logp, scheme)
	}
	cl.serverName, cl.raddr.IP, port = libnet.ParseIPPort(rurl.Host, port)
	if cl.raddr.IP == nil {
		cl.raddr.IP, err = lookup(cl.serverName)
		if err != nil {
			return nil, err
		}
		if cl.raddr.IP == nil {
			err = fmt.Errorf("smtp: %s: '%s' does not have MX record or IP address", logp, cl.serverName)
			return nil, err
		}
	}
	cl.data = make([]byte, 4096)
	cl.raddr.Port = int(port)
	if debug.Value >= 3 {
		fmt.Printf("smtp: %s: remote address '%v'\n", logp, cl.raddr)
	}
	_, err = cl.connect(localName)
	if err != nil {
		return nil, fmt.Errorf("%s: %w", logp, err)
	}
	if debug.Value >= 3 {
		fmt.Printf("smtp: %s: ServerInfo: %+v\n", logp, cl.ServerInfo)
	}
	return cl, nil
}
func (cl *Client) Authenticate(mech Mechanism, username, password string) (
	res *Response, err error,
) {
	var cmd []byte
	switch mech {
	case MechanismPLAIN:
		b := []byte("\x00" + username + "\x00" + password)
		initialResponse := base64.StdEncoding.EncodeToString(b)
		cmd = []byte("AUTH PLAIN " + initialResponse + "\r\n")
	default:
		return nil, fmt.Errorf("client.Authenticate: unknown mechanism")
	}
	return cl.SendCommand(cmd)
}
func (cl *Client) connect(localName string) (res *Response, err error) {
	logp := "connect"
	cl.conn, err = net.DialTCP("tcp", nil, cl.raddr)
	if err != nil {
		return nil, err
	}
	if cl.isTLS {
		tlsConfig := &tls.Config{
			ServerName:         cl.serverName,
			InsecureSkipVerify: cl.insecure,
		}
		cl.conn = tls.Client(cl.conn, tlsConfig)
	}
	if debug.Value >= 3 {
		fmt.Println(">>> Connected ...")
	}
	res, err = cl.recv()
	if err != nil {
		return res, fmt.Errorf("%s: %w", logp, err)
	}
	if res.Code != StatusReady {
		return res, fmt.Errorf("%s: server return %d, want 220", logp, res.Code)
	}
	res, err = cl.ehlo(localName)
	if err != nil {
		return res, fmt.Errorf("%s: %w", logp, err)
	}
	if cl.isStartTLS {
		return cl.StartTLS()
	}
	return res, nil
}
func (cl *Client) ehlo(localName string) (res *Response, err error) {
	if len(localName) == 0 {
		localName, err = os.Hostname()
		if err != nil {
			localName = getUnicastAddress()
			if len(localName) == 0 {
				err = errors.New("smtp: unable to get hostname or unicast address")
				return nil, err
			}
			localName = "[" + localName + "]"
		}
	}
	req := []byte("EHLO " + localName + "\r\n")
	res, err = cl.SendCommand(req)
	if err != nil {
		return nil, err
	}
	if res.Code == StatusOK {
		cl.ServerInfo = NewServerInfo(res)
		return res, nil
	}
	err = fmt.Errorf("smtp: EHLO response code %d, want 250", res.Code)
	return res, err
}
func (cl *Client) Expand(mlist string) (res *Response, err error) {
	if len(mlist) == 0 {
		return nil, nil
	}
	cmd := []byte("EXPN " + mlist + "\r\n")
	return cl.SendCommand(cmd)
}
func (cl *Client) Help(cmdName string) (res *Response, err error) {
	cmd := []byte("HELP " + cmdName + "\r\n")
	return cl.SendCommand(cmd)
}