TOC

Go SMTP 发送邮件

package main

import (
    "crypto/tls"
    "errors"
    "fmt"
    "net"
    "net/smtp"
)

// ============================================================================

type Transaction struct {
    Host      string
    Port      uint16
    LocalName string
    TlsEnable bool
    Username  string
    Password  string
    MailFrom  string
    RcptTo    []string
    Data      []byte
}

func NewTransaction() Transaction {
    trans := Transaction{}
    return trans
}

func (trans Transaction) Send() error {
    addr := fmt.Sprintf("%s:%d", trans.Host, trans.Port)

    // SendMail(addr string, a Auth, from string, to []string, msg []byte) error
    c, err := smtp.Dial(addr)
    if err != nil {
        return err
    }
    defer c.Close()

    c.Hello(trans.LocalName)

    if ok, _ := c.Extension("STARTTLS"); ok {
        serverName, _, _ := net.SplitHostPort(addr)
        config := &tls.Config{
            InsecureSkipVerify: true,
            ServerName:         serverName,
        }
        if err = c.StartTLS(config); err != nil {
            return err
        }
    } else {
        fmt.Printf("smtp: server doesn't support STARTTLS\n")
    }

    if trans.Username != "" {
        if ok, _ := c.Extension("AUTH"); !ok {
            return errors.New("smtp: server doesn't support AUTH")

        }
        auth := smtp.PlainAuth("", trans.Username, trans.Password, trans.Host)
        if err = c.Auth(auth); err != nil {
            fmt.Println("smtp: authentication failed")
            return err
        }
    }

    if err = c.Mail(trans.MailFrom); err != nil {
        return err
    }

    for _, addr := range trans.RcptTo {
        if err = c.Rcpt(addr); err != nil {
            return err
        }
    }

    w, err := c.Data()
    if err != nil {
        return err
    }

    _, err = w.Write(trans.Data)
    if err != nil {
        return err
    }

    err = w.Close()
    if err != nil {
        return err
    }

    return c.Quit()
}

// ============================================================================

func main() {
    from := "ninedoors@126.com"
    to := "ninedoors@qq.com"
    msg := []byte{}
    fmt.Println("============================================================")
    trans := Transaction{
        "smtp.126.com", 25, "peach", false,
        from, "password",
        from, []string{to},
        msg,
    }
    trans.Send()
}
  1. net/smtp 没有发现有好的日志实现,我只能定制了一个版本实现了日志
  2. smtp.Client -> textproto.Conn -> textproto.Writer