Skip to content

Instantly share code, notes, and snippets.

@CzBiX
Created July 26, 2020 13:21
Show Gist options
  • Select an option

  • Save CzBiX/bd69c9e342e89c75b203b100d0cafa42 to your computer and use it in GitHub Desktop.

Select an option

Save CzBiX/bd69c9e342e89c75b203b100d0cafa42 to your computer and use it in GitHub Desktop.

Revisions

  1. CzBiX created this gist Jul 26, 2020.
    134 changes: 134 additions & 0 deletions mail.go
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,134 @@
    package main

    import (
    "crypto/tls"
    "flag"
    "fmt"
    "io/ioutil"
    "net"
    "net/smtp"
    "os"
    "os/user"
    "strings"
    )

    const sslPort = 465

    func main() {
    subject := flag.String("subject", "", "subject")

    flag.Parse()

    address := flag.Arg(0)
    if address == "" {
    panic("Invalid email address")
    }

    msg := getMessage(*subject)

    err := sendMail(address, msg)
    if err != nil {
    panic(err)
    }
    }

    func sendMail(to string, msg []byte) error {
    mailname := getMailname()
    from := fmt.Sprintf("%s@%s", getUsername(), mailname)

    server, conn := getServerConn(to)

    c, err := smtp.NewClient(conn, server)
    if err != nil {
    return err
    }

    defer c.Close()

    if err = c.Hello(mailname); err != nil {
    return err
    }

    if err = c.Mail(from); err != nil {
    return err
    }
    if err = c.Rcpt(to); err != nil {
    return err
    }

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

    _, err = w.Write(msg)
    if err != nil {
    return err
    }
    err = w.Close()
    if err != nil {
    return err
    }

    return c.Quit()
    }

    func getUsername() string {
    user, err := user.Current()
    if err != nil {
    panic(err)
    }

    return user.Username
    }

    func getMailname() string {
    data, err := ioutil.ReadFile("/etc/mailname")
    if err != nil {
    hostname, err := os.Hostname()
    if err != nil {
    panic(err)
    }

    return hostname
    }

    content := string(data)
    return strings.TrimSpace(strings.SplitN(content, "\n", 1)[0])
    }

    func getServerConn(address string) (string, *tls.Conn) {
    server := strings.Split(address, "@")[1]
    mxs, err := net.LookupMX(server)
    if err != nil {
    panic(err)
    }

    host := mxs[0].Host

    tlsConfig := &tls.Config{
    ServerName: server,
    }

    conn, err := tls.Dial("tcp", fmt.Sprintf("%s:%d", host, sslPort), tlsConfig)
    if err != nil {
    panic(err)
    }

    return server, conn
    }

    func getMessage(subject string) []byte {
    buf, err := ioutil.ReadAll(os.Stdin)
    if err != nil {
    panic(err)
    }

    if subject == "" {
    return buf
    }

    h := fmt.Sprintf("Subject: %s\r\n\r\n", subject)
    buf = append([]byte(h), buf...)
    return buf
    }